Java之多态与集合的那些事

 

public class A {

    public void eat(){
        System.out.println("this is A's eat way");
    }
}

public class B extends A {
    @Override
    public void eat() {
        System.out.println("this is B's eat way");
    }
}
public class C extends A {
    @Override
    public void eat() {
        System.out.println("this is C's eat way");
    }
}
 

 

 

 

第一点 数组中的多态:

   假设class B extends class A,对于数组来说,方法takeTesting中参数声明为父类A数组,但是此方法在执行eat时,是可以区分A和B的对象的

 out put:

 

 

 第二点ArrayList中的多态(1),当传入和声明一样的参数类型时

  我们仅对go()方法和takeTesting做修改,调用takeTesting 方法也是可以正确识别A或者B对象的

 

public class D {

    public void go() {
        ArrayList<A> alist = new ArrayList<A>();
        alist.add(new B());
        alist.add(new A());
        takeTesting(alist);
    }

    private void takeTesting(ArrayList<A> aa) {
        for (A a : aa) {
            a.eat();
        }
    }

    public static void main(String[] args) {
            new D().go();
    }

}

  依旧返回

this is B's eat way
this is A's eat way

 第三点ArrayList中的多态(2),当传入和声明不一样的参数类型时,就会编译不通过

假设class B extends class A ,那么当声明 List<A>时,传参数就不能用List<B>

 

 

为什么会这样呢?--》假如编辑器允许上面操作的话,那么下面这段代码就有问题了,理论上把C对象加到ArrayList<A>是合法的,但如果我们允许传入一个B的ArrayList给该方法,那么结果就是一个被C给混进去的B集合,原本不可能出现的C的ArrayList<B>在这种情况下就出现了,这就是为什么编译器不让这种通过的原因!!

所以,如果把方法声明成取ArrayList<A>,他就只能取用ArrayList<A>参数,ArrayList<B>和ArrayList<C>都不行,此处没有多态的位置

    

private void takeTesting(ArrayList<A> aa) {
        aa.add(new C());
    }

 

同样的问题,还出现在ArrayList声明的时候,如下

 

 

 

 

 

 

可以再深入探讨下,以下对于数组的参数应该也有同样问题->

 

    public static void main(String[] args) {
        new D().go();
    }


    private void takeTesting(A[] alist) {
        alist[0] = (new C());
    }

    public void go() {
        B[] blist = {new B(),new B()};
        takeTesting(blist);
    }

//把C加到B的数组里,虽然骗过了编译器,但是会在运行时报错:Exception in thread "main" java.lang.ArrayStoreException: kevinDemo.C

 

  所以,我们可以发现,数组的类型是在运行期间检查的,而集合的类型检查只会发生在编译期间

 

 

 

语法小坑:以下用list的add方法往集合中加值这种写法是不能出现在类的声明中的,方法的调用只能放在方法中,要不然最后编译后,这个add方法的执行就是类似

new D().list.add()--> 这肯定是错误的,因为list不是D对象的属性,不能用dot符号去引用

 

继续 集合的几种赋值方式->

ArrayList 的几种赋值方法:

方式一:
List<String> list = new ArrayList<String>();
String str01 ="test1";
String str02 = "test2";
list.add(str01);
list.add(str02);
方式二:

   List<String> list = new ArrayList<String>(){{add("test1"); add("test2");}};

 

再用forEach 遍历出来

list.forEach(item->System.out.println(item));

 方式三:

  List<String> list = new ArrayList<>(Arrays.asList("test1","test2"));

OR

  List<String> myList = Arrays.asList("Apple", "Orange");

最后一个方法的myList是个固定大小的数组因为

asList 返回一个由指定数组生成的固定大小的 List。

asList 方法返回的确实是一个 ArrayList ,但这个 ArrayList 并不是 java.util.ArrayList ,而是 java.util.Arrays 的一个内部类。这个内部类用一个 final 数组来保存元素,因此用 asList 方法产生的 ArrayList 是不可修改大小的
 
方式四: list 对象赋值给list2
 

 

 这里有比较两个list是否相同,其实两个list只是内容相同,但是是两个不同对象,为什么会equals相等呢,这个要从ArrayList的equals方法 说起,

 equals方法内部在对列表元素进行逐个比较时,调用了元素的equals方法,这里其实就是调用了String的equals 方法,因为String有覆盖这个equals方法,所以上面语句才会返回true,

当然我们也可以根据需求对列表元素的equals方法进行重写,实现自己的比较逻辑

 1 public boolean equals(Object o) {
 2     if (o == this)
 3         return true;
 4     if (!(o instanceof List))
 5         return false;
 6  
 7     ListIterator<E> e1 = listIterator();
 8     ListIterator e2 = ((List) o).listIterator();
 9     while (e1.hasNext() && e2.hasNext()) {
10         E o1 = e1.next();
11         Object o2 = e2.next();
12         if (!(o1==null ? o2==null : o1.equals(o2)))
13             return false;
14     }
15     return !(e1.hasNext() || e2.hasNext());
16 }

 

posted @ 2020-08-03 09:12  波斯程序猿  阅读(223)  评论(0)    收藏  举报