我是靠谱客的博主 眼睛大路人,这篇文章主要介绍JAVA| 泛型知识点全面总结—参考JAVA核心技术 卷一第五版,现在分享给大家,希望可以做个参考。

泛型的定义

  1. 定义泛型类
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class Demo1 { public static void main(String[] args) { Pair<Integer,String> pair = new Pair<>(); pair.first = 1; pair.second = 2; pair.third = "3"; } } class Pair<T, V> { public T first; public T second; public V third; }

2.定义泛型方法(调用时不用指定类型,除非编译器无法推断出时)

复制代码
1
2
3
4
5
6
7
8
9
class Methods<T>{ public static <T> T getName(T info) { return info; } } Methods<String> methods = new Methods<>(); Object o = Methods.getName(5); System.out.println(""+ o.getClass().getSimpleName());//输出Integer

当在泛型类中定义泛型方法时 泛型方法应与类的泛型标记不一致,否则编译器会提示警告, 但实际匹配仍以泛型方法运行时检测类型为准

复制代码
1
2
3
4
5
6
7
class Methods<T>{ public <T> T getName(T info) { return info; } }

泛型的限定

  1. 使用关键词 extends;
  2. 如有多个可使用&分隔,并且传入的参数类型必须同时满足extends后面的类型;
  3. extends后面可以是类,抽象类,接口;
  4. 建议extends后面的类型标签接口(无方法接口)放在最后一个;
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Animal implements Common{ void speak(){ System.out.println("speak"); } @Override public void who() { System.out.println("Animal"); } } interface Common { void who(); } Test.test(new Animal());

泛型代码与虚拟机

类型擦除

  1. java的泛型存在于编译阶段,编译成字节码时无泛型,虚拟机里是没有泛型的;
  2. 泛型类型都会应原始类型,原始类型就是删除类型参数后的泛型类型名,擦除类型变量,并替换成限定类型(无限定的用Object);
  3. 当限定类型有多个的时候,选择第一个类型来替换;

翻译泛型表达式

复制代码
1
2
3
4
5
6
Pair<String, Integer> pair ... String s = pair.getKey(); ----------------------------- 编译器会翻译成 String s = (String) pair.getKey();

编译器会翻译成两条指令:

  1. 对原始方法的调用;
  2. 返回的Object强转为指定类型;

翻译泛型方法

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Child extends Root<Integer> { public void setNum(Integer a) { super.setNum(a); } } class Root<T> { private T num; public void setNum(T num) { this.num = num; } } Child child = new Child(); Root<Integer> root = child; //多态 root.setNum(10);

编译器会翻译成

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
class Child extends Root { public void setNum(Integer a) { super.setNum(a); } } class Root { private Object num; public void setNum(Object num) { this.num = num; } }

由于super调用的是重写方法,但重写必须满足以下要求

  • 参数列表必须完全与被重写方法的相同
  • 返回类型与被重写方法的返回类型可以不相同,但是必须是父类返回值的派生类(java5 及更早版本返回类型要一样,java7 及更高版本可以不同)。
  • 访问权限不能比父类中被重写的方法的访问权限更低。例如:如果父类的一个方法被声明为 public,那么在子类中重写该方法就不能声明为 protected。
  • 父类的成员方法只能被它的子类重写。
  • 声明为 final 的方法不能被重写。
  • 声明为 static 的方法不能被重写,但是能够被再次声明。
  • 子类和父类在同一个包中,那么子类可以重写父类所有方法,除了声明为 private 和 final 的方法。
  • 子类和父类不在同一个包中,那么子类只能够重写父类的声明为 public 和 protected 的非 final 方法。
  • 重写的方法能够抛出任何非强制异常,无论被重写的方法是否抛出异常。但是,重写的方法不能抛出新的强制性异常,或者比被重写方法声明的更广泛的强制性异常,反之则可以。
  • 构造方法不能被重写。
  • 如果不能继承一个方法,则不能重写这个方法。 

我再补充一下重载

  • 被重载的方法必须改变参数列表(参数个数或类型不一样);
  • 被重载的方法可以改变返回类型;
  • 被重载的方法可以改变访问修饰符;
  • 被重载的方法可以声明新的或更广的检查异常;
  • 方法能够在同一个类中或者在一个子类中被重载。
  • 无法以返回值类型作为重载函数的区分标准。

重写与重载之间的区别

区别重载重写
参数列表必须修改不能更改
返回类型可以修改不能更改
异常可以修改可以减少或删除,一定不能抛出新的或者更广的异常
访问可以修改一定不能做更严格的限制(可以降低限制)

所以super无法访问父类的public void setNum(Integer a) 因此,编译器会在子类中自动生成一种桥方法

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Child extends Root { public void setNum(Integer a) { super.setNum(a); } public void setNum(Object a) { setNum((Integet)a); } /* 不能自定义桥方法 否则编译器报错 //ERROR public void setNum(Object a) { setNum((Integet)a); } */ }

Java泛型转换:

  1. 虚拟机中没有泛型,只有普通的类和方法;
  2. 所有的类型参数都用他们的限定类型替换;
  3. 桥方法的合成是用来保持多态;
  4. 为保证类型安全性,必要时插入强制类型转换;

约束与局限性

1.不能用基本类型实例化类型参数 2.运行时类型查询只适用于原始类型

复制代码
1
2
3
4
5
6
7
8
9
10
class Things<T> { } class Animal { } class People { } Things<Animal> things = new Things<>(); Things<People> peopleThings = new Things<>(); System.out.println(""+things.getClass().getName());// Things System.out.println(""+peopleThings.getClass().getName());// Things boolean a = things instanceof Things<Animal>; // 编译器报错 不允许这样操作 boolean b = things instanceof Things; // 编译器提醒一直为true

3.不能创建参数化类型的数组, 不能构造泛型数组:

复制代码
1
2
3
Things<Animal>[] things;// 可以声明 但不能new Things<Animal>[] things = (Things<Animal>[])new Things<?>[10];// 编译器报警告 但不安全

4.可变参数列表中是泛型类型的方法前需加@SafeVarargs

复制代码
1
2
3
4
5
6
7
8
9
@SafeVarargs private static<T> void add(List<T> list, T... args) { list.addAll(Arrays.asList(args)); } Things<Animal> things1 = new Things<>(); Things<Animal> things2 = new Things<>(); List<Things<Animal>> list = new ArrayList<>(); add(list, things1, things2);

5.不能实例化类型变量

复制代码
1
2
3
4
class Things<T> { private T arg1 = new T();// 编译器报错 }

正确使用应该是利用函数接口或者使用反射(需增加try):

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
class Things<T> { private T arg1; Things(T arg1) { this.arg1 = arg1; } public void getArg1() { System.out.println("type:"+arg1.getClass().getSimpleName()+" v"+arg1); } } /** * @param construct,表示一个无参数而且返回类型为 T 的函数 */ private static <T> Things<T> getObject(Supplier<T> construct) { return new Things<>(construct.get()); } /** * 使用反射方法 添加Try Catch */ private static <T> Things<T> getObject(Class<T> construct) { try { return new Things<>(construct.newInstance()); } catch (InstantiationException | IllegalAccessException e) { e.printStackTrace(); } return null; } Things<String> things = getObject(String:: new); // 或者 Things<String> things1 = getObject(String.class); things.getArg1(); assert things1 != null; things1.getArg1();

6.泛型类的静态上下文中类型变量无效(静态属性不能含有泛型) 考虑Singleton<Random>

复制代码
1
2
3
4
5
6
7
8
9
public class Singleton<T> { private static T singlelnstance; // Error public static T getSinglelnstanceO // Error { if (singleinstance == null) construct new instance of T return singlelnstance; } }

7.不能抛出或捕获泛型类的实例

catch 子句中不能使用类型变量

泛型类扩展 Throwable 都是不合法的

在异常规范中使用类型变量是允许的

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 无法编译 public static <T extends Throwable> void doWork(Class<T> t) { try { do work } catch (T e) // Error can 't catch type variable { Logger,global.info(...); } } // 可以通过 public static <T extends Throwable> void doWork(T t) throws T {// OK try{ do work; } catch (Throwable realCause){ t.initCause(realCause); throw t; } }

8.可以消除对受查异常的检查

就是将所有异常都包装成指定的一个异常抛出

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
class Block{ @SuppressWarnings("unchecked") public static <T extends Throwable>void throwAs(Throwable e) throws T { throw (T) e; } } // 将任何异常都指定为RuntimeException try { do work; }catch (Throwable t) { B1ock.<RuntimeException>throwAs(t) ; }

通配符类型

  • 格式: TypeClass<? extends Root〉
  • 通配符的超类型限定 TypeClass<? super Manager> 
  • 无限定通配符 TypeClass<?>

 

最后

以上就是眼睛大路人最近收集整理的关于JAVA| 泛型知识点全面总结—参考JAVA核心技术 卷一第五版的全部内容,更多相关JAVA|内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(61)

评论列表共有 0 条评论

立即
投稿
返回
顶部