带你走进java-第十四章.泛型,数组转集合,Set接口-HashSet实现类(重点:去重)

泛型

1.泛型的概念:
  泛型: 标识着 集合中存储元素的数据类型
  写法: <数据类型(即泛型)>
// 泛型的写法:
    // 创建一个集合 ,保存a b c d
    // E  泛型  Element(元素)
    // 注意:前后泛型的类型要保持一致(如果后面要填的话)
    // jdk1.7 菱形泛型
    // 后面泛型可以不填 默认和前面的一致  
    ArrayList<String> list = new ArrayList<>();
    list.add("a");
    list.add("b"); 
    list.add("c"); 
    list.add("d");
    // 利用迭代器遍历
    // 迭代器泛型 表示集合中保存的元素类型 [与实现类中的泛型保持一致]
    Iterator<String> iterator = list.iterator();
    while(iterator.hasNext()){
        String next = iterator.next();
        System.out.println(next);
        // 如果是自己写的类的对象,需要重写toString()
    }   
2.泛型的好处
  1️⃣保证了数据的安全性 (提示你 方法中要传入的数据类型)
  2️⃣避免了 向下转型(类型强转) [提示你 创建什么类型的对象接受迭代器传来的数据]
  3️⃣将运行时的错误 转化成了编译错误 [类型接受错误时,不需要运行报错,直接提示]
//   创建集合 保存3学生
//   获取集合中的第0个学生 并打印姓名

ArrayList<Student> list = new ArrayList<>();
list.add(new Student("东东", 16)); // 好处 1️⃣:提示你方法中传入学生类对象
list.add(new Student("生生", 18));
list.add(new Student("柳柳", 20));
Object object = list.get(0);
Student student = (Student) object; // 好处 2️⃣:可以不用向下转型,直接用学生类对象接受
// 好处 3️⃣:若接受对象不对,不用运行才报错,直接报错(一般在迭代器中比较明显)
3.泛型的声明
  1️⃣声明位置:  类名(接口名)<泛型> 
     假如:Student<S>   此时S是占位符
    注意: 泛型使用占位符(英文字符)时 一般使用大写字母
  2️⃣什么时候 指定泛型的真正类型?
    创建对象时 会给泛型 赋值数据(对象)类型
// 举例:泛型的声明 与 指定数据类型

// 泛型的声明位置 (Worker类中属性的数据类型都为W)
class Worker<W>{
    // 利用泛型 声明成员变量
    private W w;
    // 声明set/get方法
    public void setW(W w) {
        this.w = w;
    }
    public W getW() {
        return w;
    }
    // 成员方法
    public void fun(W w) {
        System.out.println(w);
        System.out.println("我是fun方法");
    }
    // 一个类中 可不可以有多个泛型?  可以
    // 需要在方法上 进行泛型的声明
    // 这个泛型 将会在 该方法被调用的时候  被传参(不一定是该类对象的属性)赋值
    public<Y> void fun1(Y y) {
        System.out.println(y);
    }
    // 静态方法   能不能使用  W  泛型 ?   不能
    // 当方法被调用时,泛型被赋值
    public static<Q> void fun2(Q q) {
        System.out.println(q);
    }
}
//  指定泛型的真正数据类型
// 此时泛型占位符W  被赋值  String
    Worker<String> worker = new Worker<>();
    worker.setW("wangjun");
    System.out.println(worker.getW());
    worker.fun("少年强则中国强");
    worker.fun1('1'); // 传入的参数是字符,该Y被赋值char
// 接口中的泛型

// 泛型接口
interface InterA<G>{
    public abstract void fun(G g);
}
// 泛型类型确定 可以在 接口的实现类上确定
class InterAImpl implements InterA<String>{
    @Override
    public void fun(String g) {
        // TODO Auto-generated method stub

    }
}

多参数方法(int … num)

int ... num (输入int类型 从0到num)
可以接受多个 int类型值  相当于参数是一个数组[0,1,...num]
调用方式两种
1.传入多个值  用逗号隔开
2.直接传入数组
// 第一种方法(传入多个值,逗号隔开)调用
注意:可以添加不同类型的参数,但是要放在前面,放在后面会报错
         (换句话说: int ... num 要放在最后面)
    public static void print(String str,int ... num) {
            // 遍历(获取你传进来有几个int值)
            for (int i = 0; i < num.length; i++) {
                System.out.println(num[i]);
            }
        }
// 第二种方法(输入数组)隔开
    int[] arr = {2,3,4,5};
    print(" ",arr);

数组转集合:Arrays.asList(数组名),记住用集合接收

// ❎ 错误的 原因:集合中只能放引用类型的数据,不能放基本数据类型
int[] array = {1,2,3,4,5};
List<int[]> list = Arrays.asList(array);
System.out.println(list);
// ✔️ 正确的 装箱了   
Integer[] array1 = {1,2,3,4,5};
List<Integer> list1 = Arrays.asList(array1);
System.out.println(list1);
//  创建一个字符串数组 保存三个名字
//  将数组 转成集合 
//  添加一个名字
String[] arr = {"东东","生生","柳柳"};
// 将数组 转成 集合
List<String> list2 = Arrays.asList(arr);
System.out.println(list2);
// 添加名字
// UnsupportedOperationException
// 不支持操作异常
// 注意:该方法 转完集合后 不支持对集合的长度修改
// list.add("花花");
// 该方法意义在于: 可以使用集合类中 其他方法
boolean b = list2.contains("生生");
System.out.println(b);

4.泛型在继承中的应用: 将子类或本类放入集合中
//  前提: class Student extends Person
//  举例:
    ArrayList<Person> list = new ArrayList<Person>();
    list.add(new Student()); // 添加子类
    list.add(new Person()); // 添加本类

去重删除

一般两种方法 1.for循环删除  2.迭代器删除
ArrayList<String> list = new ArrayList<>();
list.add("a");
list.add("b");
list.add("b");
list.add("c");
list.add("d");   [a,b,b,c,d] 删除两个b
// 1.for循环删除
for (int i = 0; i < list.size(); i++) {
        String string = list.get(i);
        if (string.equals("b")) {
            list.remove(i--);
            // 删除一个,其他的前移一位,若两个连续,则只能删除一个
            // --,是为了循环在再进行一次,删除下一个b
        }
}
System.out.println(list);

// 2.迭代器删除
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
    String str = iterator.next();
    if (str.equals("b")) {
        iterator.remove();
    }
}
System.out.println(list);

集合工具类:Collection.swap(list,i,j) 交换位置

Set接口-HashSet实现类

1.HashSet实现类的特点: 无序  无角标  不可重复(继承Set接口)
  自带去重 (前提:对象地址重复,才能去重,不能根据属性直接去重) 
2.HashSet集合的建立
// 创建Set集合  添加a a b b c c 
// 有序: 指的是存取的顺序  存的顺序就是取的顺序
// 迭代器遍历
HashSet<String> set = new HashSet<>();
set.add("f");
set.add("a");
set.add("a");
set.add("b");
set.add("b");
set.add("c");
set.add("c");
// 迭代器遍历
Iterator<String> iterator = set.iterator();
while (iterator.hasNext()) {
    String string = (String) iterator.next();
    System.out.println(string);
}
结果:
a,b,c,f(无序)
3.Set的自动去重
HashSet<Man> set = new HashSet<>();
Man m1 = new Man("1",11);
Man m2 = new Man("1",11);
Man m3 = new Man("2",22);
Man m4 = new Man("2",22);
Man m5 = new Man("3",33);
Man m6 = new Man("3",33);
set.add(m1);
set.add(m2);
set.add(m3);
set.add(m4);
set.add(m5);
set.add(m6);
Iterator<Man> iterator = set.iterator();
while (iterator.hasNext()) {
    Man m = (Man) iterator.next();
    System.out.println(m);
}
直接输出结果: 一个没删            
没去重原因:
// 系统每创建一个对象 都会为这个对象
// 分配一个 hashCode值
// 当向HashSet集合中 保存对象时
// 系统会先比较hashCode值是否相同

// 相同: 再调用对象的equals方法进行比较,
//      如果equals方法比较也相同,那么就不存
//      反之,会存储到集合中

// 不相同: 如果HashCode不相同,就相当于不是一个对象
//        那么直接就把该对象 直接存入集合中
//        也不会调用equals方法

解决办法:
// 重写hashCode和equals方法
// 举例

/*
* 随机10个数  [10,20] 装到集合中去重
* Integer可以直接去重
* String可以直接去重
* 系统已经重写好了hashCode()方法和equals()方法
* 自己写的类没有写好,所以自己要重写
*/
        HashSet<Integer> set  = new HashSet<>();
        for (int i = 0; i < 10; i++) {
            int num = (int)(Math.random() * 11 + 10);
            set.add(num);// 自动装箱
        }
        System.out.println(set);

猜你喜欢

转载自blog.csdn.net/qq_35368276/article/details/82466507
今日推荐