第一次接触 java 的时候,一次编译,到处运行,给人的感觉就很强大,必须入坑啊。不过现在 java 主流使用场景还是后端这块,图形化界面开发并不擅长。java 在后端语言的竞争中依然屹立不倒,和 java 的生态有很大关系,但不可否认的是,java 在高并发场景下的稳定性确实可靠。今天还看了一个关于够浪(golang) 语言的评价,也准备考虑入门下作为技术储备。有时间学习的时候,我一定要多学点。
最近打算花时间重拾 java ,决定看看 jdk 源码,再提升一个层次。也想写一个关于 java 和 SpringBoot 的系列博客。
当我入坑 java 的时候,那时候还是 jdk 1.7 的天下。不过泛型确实是个好东西。没有泛型之前我们可能会这样写代码
@Test public void run1() { // 有个集合你想保存 String 类型数据 List list =new ArrayList(); list.add("1111"); String o = (String) list.get(0); System.out.println(o.length()); // 可能会导致别的开发人员存储的是 int 类型 list.add(2222); } 复制代码
上述代码存在的问题:
1.7 增加的特性 菱形泛型我掺杂到一起说了
// 有个集合你想保存 String 类型数据 List<String> list =new ArrayList(); list.add("1111"); String s = list.get(0); System.out.println(s.length()); // 下列会在编译时期就会报错 // list.add(2222); 复制代码
是不是喜大普奔,不那么反人类了
泛型:参数类型化
public class ClientTest<T> { /** * 验证泛型可以在类上和方法上声明 * 不能这样 <K1 super Parent> */ public <T2 extends ArgsParent> T2 run2(T k) { System.out.println(k.getName()); System.out.println(k); return (T2) k; } } 复制代码
以上验证了泛型可以在类上和方法上声明
package com.fly.study.java.generics; import org.junit.Before; import org.junit.Test; import java.util.ArrayList; import java.util.List; /** * @author 张攀钦 * @date 2019-09-16-00:04 * @description 泛型验证 */ public class ClientTest<T> { private ClientTest clientTest; private Parent parent; private Son son; private ClientTest<Son> sonClientTest; private ArgsParent argsParent; private ArgsSon argsSon; /** * 限制方法参数的泛型和返回值类型,泛型优先使用方法上的,当方法上没有使用类上的 * 不能这样 <K1 super Parent> */ public <T extends ArgsParent, T2 extends ArgsParent> T2 run2(T k) { System.out.println(k.getName()); System.out.println(k); return (T2) k; } @Before public void before() { clientTest = new ClientTest(); parent = new Parent(); parent.setName("parent"); son = new Son(); son.setAge(18); sonClientTest = new ClientTest<>(); argsParent = new ArgsParent(); argsParent.setName("argsParent"); argsSon = new ArgsSon(); } @Test public void test2() { System.out.println(clientTest.run2(argsParent)); System.out.println(clientTest.run2(argsSon)); // 验证方法上的泛型优先于类上的泛型 sonClientTest.run2(argsSon); // 下面用法错误 // sonClientTest.run2(son); } } @Data public class ArgsParent { private String name; } @Data public class ArgsSon extends ArgsParent { private Integer age; } @Data public class Parent { private String name; } @Data public class Son extends Parent { private Integer age; } 复制代码
我在类上和方法上使用了同一个泛型 T ,但是类型限制不同,类上泛型 T 我在 new 对象的时候是 ClientTest sonClientTest,而我在方法上指定了T 为 ,运行方法的时候,如果参数只能传入 ArgsParent及其子类即可验证我的结论。
// public class ClientTest<T> // public <T extends ArgsParent, T2 extends ArgsParent> T2 run2(T k) // argsSon 为 ArgsParent 的子类对象 sonClientTest.run2(argsSon); // 下面用法错误,son 为 Son 的实例对象 // sonClientTest.run2(son); 复制代码
public class ClientTest<T> { /** * 静态方法上的泛型不能使用类上的,只能再方法上声明泛型 */ public static <T extends ArgsParent, T2 extends ArgsParent> void run4(T k) { System.out.println(k); } // 语法错误 public static void run4(T k) { System.out.println(k); } } 复制代码
字面意思理解泛型限定符很方便,代码中的注释即可说明意思
// 限定参数类型只能为 ArgsParent及其子类 <S extends ArgsParent> // 语法错误,jdk 1.8 <S super ArgsParent> // 限定参数类型只能为 ArgsParent 及其子类 <? extends ArgsParent> // 限定参数只能为 ArgsParent 及其父类 <? extends ArgsParent> 复制代码
public class AllGenerics<T> { public void run1(T t) { System.out.println(t); } public <S> void run2(S s) { System.out.println(s); } // 限定参数类型只能为 ArgsParent及其子类 public <S extends ArgsParent> void run3(S s) { System.out.println(s); } // 语法错误, // public <S super ArgsParent> void run3(S s) { // System.out.println(s); //} // 限定参数类型只能为 ArgsParent及其子类 public void run4(List<? extends ArgsParent> s) { System.out.println(s); } // 限定参数只能为 ArgsParent及其父类 public void run5(List<? super ArgsParent> s) { System.out.println(s); } } 复制代码
泛型只在编译期有效,编译之后会对泛型声明进行替换,对于能确定类型的使用确定类型,不确定的使用 Object 代替。
// 源码 public class AllGenerics<T> { public void run1(T t) { System.out.println(t); } } // 编译之后的代码可以这样理解 public class AllGenerics<Object> { public void run1(Object t) { System.out.println(t); } } 复制代码
public class AllGenerics<T> { public <S extends ArgsParent> void run2(S s) { System.out.println(s); } } // 编译之后的代码可以这样理解 public class AllGenerics<ArgsParent> { public void run1(ArgsParent t) { System.out.println(t); } } 复制代码
@Data public class ClientTestSuperT { @Test public void test1() throws Exception{ List<String>t=new ArrayList<>(); Method add = t.getClass().getMethod("add",Object.class); // 添加 Integer 类型数字 add.invoke(t,1); System.out.println(t); } } 复制代码
package com.fly.study.java.generics; import org.junit.Test; import java.lang.reflect.Method; public class AllGenerics<T> { public <S extends ArgsParent> void run2(S s) { System.out.println(s); } public void run1(T t) { System.out.println(t); } @Test public void test1() throws Exception { AllGenerics<String> allGenerics =new AllGenerics<>(); Method method= allGenerics.getClass().getMethod("run1", Object.class); // java.lang.NoSuchMethodException: // com.fly.study.java.generics.AllGenerics.run1(java.lang.String) // Method method= allGenerics.getClass().getMethod("run1", String.class); method.invoke(allGenerics,"111"); } @Test public void run2() throws Exception { AllGenerics<String> allGenerics =new AllGenerics<>(); Method method= allGenerics.getClass().getMethod("run2", ArgsParent.class); ArgsParent argsParent = new ArgsParent(); argsParent.setName("测试"); // java.lang.NoSuchMethodException: // com.fly.study.java.generics.AllGenerics.run1(java.lang.String) // Method method= allGenerics.getClass().getMethod("run2", Object.class); method.invoke(allGenerics,argsParent); } } 复制代码
AllGenerics<T> 编译之后 AllGenerics<Object> // 编译之后为 public void run1(Object t) public void run1(T t) { System.out.println(t); } // 编译之后 public void run2(ArgsParent s) public <S extends ArgsParent> void run2(S s) { System.out.println(s); } 复制代码
@Test public void test1() throws Exception { AllGenerics<String> allGenerics =new AllGenerics<>(); Method method= allGenerics.getClass().getMethod("run1", Object.class); method.invoke(allGenerics,"111"); } 复制代码
上述代码可以正常运行,验证编译之后代码确实替换了
@Test public void test1() throws Exception { AllGenerics<String> allGenerics =new AllGenerics<>(); Method method= allGenerics.getClass().getMethod("run1", String.class); method.invoke(allGenerics,"111"); } 复制代码
上述代码运行报错 java.lang.NoSuchMethodException:com.fly.study.java.generics.AllGenerics.run1(java.lang.String),说明编译之后的代码中没有这个方法
// 方法编译之后为:public void run2(ArgsParent s) public <S extends ArgsParent> void run2(S s) { System.out.println(s); } 复制代码
@Test public void run2() throws Exception { AllGenerics<String> allGenerics =new AllGenerics<>(); Method method= allGenerics.getClass().getMethod("run2", ArgsParent.class); ArgsParent argsParent = new ArgsParent(); argsParent.setName("测试"); method.invoke(allGenerics,argsParent); } 复制代码
以上获取到了方法,说明我的猜测正确
@Test public void run2() throws Exception { AllGenerics<String> allGenerics =new AllGenerics<>(); ArgsParent argsParent = new ArgsParent(); argsParent.setName("测试"); Method method= allGenerics.getClass().getMethod("run2", Object.class); method.invoke(allGenerics,argsParent); } 复制代码
代码报错,找不到对应的方法