一点小心得
面对完全没有头绪的工作,只要开始第一步,神奇的事情就会发生,编程这件事,这一点体现的淋漓尽致,只有一行动,思路就会泉涌而来。
未来我计划以3天为一个周期,将剩余的课程按3-3-9的配额设定任务量,顺应人性不死板,3天完成15课就好,剩余时间自由支配。
刻意练习,保证质量,绝对不要骗自己,所有示例代码,自己看完示范后,按其思路改写一遍(绝对不能照抄!那是打字员的工作,不是程序员!必须完全更改,只保留思路)
更改个人自我基本假设,未来不再是自己的人比自己的事重要,而是反过来,要将自己的事看的比自己的人重要。(感谢李善友教授讲了王东岳老师的生平故事,更感谢自己能把业余时间用在听课而不是玩游戏刷肥皂剧上)
第117集:自定义泛型深入1、子类、属性类型、重写方法类型、泛型擦除
-
擦除
要么同时擦除,要么子类是泛型类,同时让子类泛型字母数都要大于等于父类(子类声明时指定具体类型的情况除外)
不可子类擦除,父类泛型。
被擦除后,原泛型字母指代的类型一律视为Object
-
属性类型(关键看属性属于父类还是子类)
父类的属性,随父类定
子类的属性,随子类定
-
方法重写:随父类定
package com.fangxing; //父类为泛型类 public abstract class Father<T1,T2>{ T1 name; public void test(T1 a){}; } //子类声明时指定具体类型,另外原来的T name此时已经变为 String name class Child extends Father<String,Integer>{ int size; public void test(String a){ } } //子类是泛型类,父类也是,另外,子类泛型字母个数等于父类 class Child2<T1,T2> extends Father<T1,T2> { int size; public void test(T1 a){ } } //泛型的字母顺序调换没有关系 class Child8<T2,T1> extends Father<T1,T2> { int size; public void test(T1 a){ } } //子类是泛型类,父类也是,另外,子类泛型字母个数大于父类 class Child3<T1,T2,T3> extends Father<T1,T2>{ T3 size; //这个T3 size属性属于子类,属性类型随子类定 public void test(T1 a){//这个方法重写,这个T1属性随父类而定 this.name = a;//这个T1 name属性属于父类,属性类型随父类定 } } //子类是泛型类,父类不指定类型(即父类进行了擦除),原来泛型字母指代的类型一律视为Object(即原来那父类那个T name 现在变成了 Object name) class Child4<T1,T2> extends Father{ int size; public void test(Object a){ } } //子类与父类均擦除,原来泛型字母指代的类型一律视为Object class Child5 extends Father{ int size; public void test(Object a){ } } //这里有错误,不能让子类泛型字母数量小于父类。 //class Child6 extends Father<T1,T2>{ // int size; // public void test(T1 a){ // // } //} //这里有错误,不能让子类泛型字母数量小于父类。 //class Child7<T1> extends Father<T1,T2>{ // int size; // public void test(Object a){ // // } //}
-
接口的泛型使用规则与类的继承一样
package com.fangxing; public interface Comparable<T> { public void test(T a); } class Comp implements Comparable<String>{ public void test(String a){} } class Comp1<T> implements Comparable<T>{ public void test(T a){} } class Comp2<T> implements Comparable{ public void test(Object a){} } class Comp3 implements Comparable{ public void test(Object a){} } // 错误 //class Comp4 implements Comparable<T>{ // public void test(Object a){} //}
-
擦除时默认设置其泛型字母代表的类型为Object,
package com.fangxing; public class Test<T> { int size; public void test(T a){ } public static void kkk1(Test<Object> a){ } public static void kkk2(Test<?> a){ } public static void kkk3(Test<Integer> a){ } public static void main(String[] args){ Test test1 = new Test(); //擦除不会在编译时进行类型检查(虽然相当于Object,但其实与Test<Object>的Object也不完全等同) //将其泛型类型设置Object,可消除警告 Test<Object> test2 = new Test<Object>(); kkk1(test1); kkk2(test1); kkk3(test1); kkk1(test2); kkk2(test2); //kkk3(test2);//报错,因为没有装入Object类型 } }
第118集:自定义泛型深入2、无多态、通配符、无泛型数组、jdk7泛型使用
多态的两种形式:
形参使用多态
-
返回类型使用多态
package test118; /** * @author wangtao * 多态的两种形式 */ public class Father { int a; //形参使用多态 public void test(Father b){ } //返回类型使用多态 public Father test2(){ return new Child(); } } class Child extends Father{ public static void main(String[] args){ Child k = new Child(); //形参发生多态 k.test(k); //返回值发生多态 k.test2(); } }
泛型没有多态
package test118;
public class GenericityClass<T> {
T test;
//测试泛型返回值是否能使用多态
public GenericityClass<Father> test01(){
//return new GenericityClass<Child>();//报错,泛型返回值不能发生多态
//return (GenericityClass<Father>)(new GenericityClass<Child>());//报错,强转也没有用
return new GenericityClass<Father>();//正确姿势
}
//测试泛型形参是否能使用多态
public void test02(GenericityClass<Father> a){
}
public static void main(String[] args){
//GenericityClass<Father> a = new GenericityClass<Child>();//报错 泛型不发生多态
GenericityClass<Father> a = new GenericityClass<Father>();
//a.test02(new GenericityClass<Child>());//报错,泛型形参不能发生多态
a.test02(new GenericityClass<Father>());//正确姿势
}
}
通配符?
-
通配符:? extends super【用于实现类似多态的效果】
? extends 泛型上限 <=
? super 泛型下限 >=
通配符可以用在声明类型及声明方法参数上,不能用在声明类上。
?可以接受泛型的任意类型,只能接收和输出,不能修改。
?类型不定,使用时确定类型。
package test118;
//public class Animal<?>{ //报错,通配符?不可用于声明类
//
//}
public class Animal<T> {
T age;
public static void test0(Animal<String> a){
}
public static void test1(Animal<?> a){
}
public static void test2(Animal<? extends Father> a){
}
public static void test3(Animal<? super Father> a){
}
public static void test4(Animal<Father> a){
}
public static void main(String[] args){
//通配符?可以接收任意类型,但是通配符只能用于声明方法参数和类型,不能用于声明类。
Animal<?> dog = new Animal<Integer>();
//Animal<?> lion = new Animal<?>();//报错,不可以实例化一个泛型为通配符?的对象
//给方法传参时,编译器的类型检查,是以声明时为准,而不是使用时,所以同样是String,一个可编译通过,一个不可以。
Animal<?> mouse = new Animal<String>();
Animal<String> cat = new Animal<String>();
test0(cat);
//test0(mouse); //报错 声明时的泛型字母为通配符?,与方法test0的形参不一样
//
test1(dog);
test1(mouse);
test1(cat);
//
Animal<Child> person1 = new Animal<Child>();
Animal<Father> person2 = new Animal<Father>();
Animal<?> python1 = new Animal<Child>();
Animal<?> python2 = new Animal<Father>();
//以下报错原因:声明时的泛型类型不适配
//test2(dog); //报错
//test2(mouse); //报错
//test2(cat); //报错
//test2(python1); //报错
//test2(python2); //报错
test2(person1); //正确 <= Father
test2(person2); //正确 <= Father
//
//test3(person1); //报错,child<= Father
test3(person2); //正确 >= Father
test3(new Animal<Object>());//正确 >= Father
//
//test4(new Animal<Child>());//报错,泛型不发生多态
}
}
泛型的嵌套
-
声明:嵌套使用泛型
A<B<C>> a = new A<B<C>>();
-
使用:从外到内,层层拆分
稍微复杂一些,但与调用没有任何关系,只是确定了类型而已。package test118; public class Test01<T> { T name; public static void main(String[] args){ Test01<GenericityClass<String>> a = new Test01<GenericityClass<String>>();//在这一步,a.name的值还为null,未指向任何对象。 a.name = new GenericityClass<String>();//若不让a.name指向一个GenericityClass对象,后续输出将报空指针异常的错误。 GenericityClass<String> b = a.name;//a.name的类型与b相同 System.out.println(b.test); } }
泛型与数组
没有什么泛型数组。
package test118;
public class Test02 {
Animal<String>[] lions;//可以声明泛型数组,但是无法创建泛型数组,没啥意义
public static void main(String[] args){
Animal[] dogs = new Animal[10];
//Animal<String>[] cat = new Animal<String>[10];//报错,可以声明泛型数组,但无法创建泛型数组,没啥意义
Animal<?>[] mouse = new Animal[10];//这样可行,但是依然无法控制传入数组的数据的类型。
//如何确保传入数组的类型按我们的要求来?
//思路是先将数据传入一个类,再用该类get方法return出来,return出来的同时进行强制转换(此时用泛型)
MyArrayList<Integer> kk = new MyArrayList<Integer>();
kk.add(0, 1);
kk.add(1, 2);
System.out.println(kk.get(0));//设定泛型为Integer类型,取出来就是Integer类型。
System.out.println(kk.getAll());
}
}
class MyArrayList<E>{
//E[] cap = new E[10];//报错,没有什么泛型数组
private Object[] cap = new Object[10];
public void add(int index,E e){
cap[index] = e;
}
public E[] getAll(){
return (E[]) cap;
}
public E get(int index){
return (E)cap[index];
}
}
JDK1.7的一个新增特性
package test118;
import java.util.HashSet;
import java.util.Set;
public class Test03 {
public static void main(String[] args){
Set<String> aa = new HashSet<String>();
Set<String> bb = new HashSet<>();//JDK1.7后,第二次使用同样的泛型可以少打几个字母了~~~
}
}