泛型的引出:
强转可能会出现类型转换异常
【集合中使用泛型】
1、<引用数据类型>,用于限制元素的类型
2、集合中使用泛型,泛型仅仅在编译时有效,在字节码中就没了,叫类型擦除
3.泛型可以放子类的类型。
【不指定泛型,默认Object,可以放任何类型,即任何Object子类都可以】
【自定义泛型类】 T相当于成员变量
什么时候把类定义为自定义泛型类??
在编译时出现了不确定的数据类型的时候,就用泛型代替。泛型在被应用时指定,被应用指的是创建对象和被继承的时候。
T :Type
E: Element
【自定义泛型方法】
方法出现了不确定类型
publicE myMethod(List list){ //方法返回值类型之前要加 ,传递的参数是什么类型,返回的就是什么类型 }
通配符:List>
List
List> 可以接收任意泛型的集合。但是我们常用的的时候还是要加类型限定的
List extends Person>可以接收Person本类 或 Person子类类型的集合。不能添加
List super Person> 可以接收Person本类 或 Person父类类型的集合,不能遍历,可以添加
以此类推,List
泛型其他内容参考我另外一篇文章:
2022/1/4 北京 泛型类,泛型继承,泛型方法_£小羽毛的博客-CSDN博客
反射:动态语言的关键
出现不确定的类型用泛型,出现不确定的对象用反射
返回数据库的一个表结构 publicT get(Class clazz){ //50行查询数据库的代码 return clazz.newInstance();//出现不确定的类型用泛型,出现不确定的对象用反射 }
反射的功能:
(1)在运行时创建任意类型的对象
(2)在运行时获取任意类型的信息
(3)在运行时获取和设置任意属性值
(4)在运行时调用任意对象的方法
Java的运行状态:
- 编译时:javac命令生成class字节码文件(一个.class字节码文件描述一个类)
- 运行时: java命令,通过jvm提供的类加载器将.class字节码文件加载到内存中
最最开始的时候__类加载:
每个类的大概内容:【在内存中的类信息】
- This_class/Super_class/Interfaces【层次结构】
- Field_info Method_info Constroctor Classes Annotation【属性表.方法表/构造器/内部类/注解】
类的初始化:
- 类的加载:创建大Class实例
- 类的连接:加载静态成员
- 类的初始化:初始化静态成员
类加载器:加载classpath指定的字节码文件到内存。
- 引导类加载器 【获取不了.getParaent()】
- 扩展类加载器
- 系统类加载器【自定义的类的字节码文件】
双亲委派模型,从最上层,一层一层往下加载【引导类加载器、扩展类加载器、系统类加载器】
@Test
public void test5() throws ClassNotFoundException {
// ClassLoader 类加载器
ClassLoader classLoader = Ticket.class.getClassLoader();
System.out.println(classLoader);
// 自定义的类都是同一个·类加载器加载的
ClassLoader classLoader2 = Person.class.getClassLoader();
System.out.println(classLoader2);
}
类加载器加载属性文件:
在部署到服务器上以后就没有盘符,也没有当前项目路径,但是类加载路径是一定有的。
类加载路径:至少得在src下。
props.load(this.getClass().getClassLoader().getResourcesAsStream());//以流的形式加载,用包路径
@Test
public void test07() throws ClassNotFoundException, IOException {
//使用类加载器加载属性文件
ClassLoader classLoader = this.getClass().getClassLoader();
//getResourceAsStream(String str):获取类路径下的指定文件的输入流
InputStream inputStream = classLoader.getResourceAsStream("hello.properties");
Properties props = new Properties();
props.load(inputStream);
System.out.println(props.get("username"));
System.out.println(props.get("password"));
}
如果properties文件在某一个包下
//包路径,不是包 用/不用.
InputStream inputStream = classLoader.getResourceAsStream("com/atgui/properties/world.properties");
Class_描述类的类 ,大Class实例是开启反射的源头
描述某个类的大Class实例,是jvm在类加载的时候在堆中自动创建。我们自己不能创建
一个类在 JVM 中只会有一个Class实例 ,单例的。
如何获取对应类的大Class实例
1.运行时类的class属性。【每个类都有】
2.运行时类的对象的getClass();
3.使用Class的静态方法forName(全限定类名,包名+类名)
4.类加载器也可以完成
//通过某一个大class实例获取类加载器
ClassLoader cl = this.getClass().getClassLoader();
Class clazz4 = cl.loadClass("类的全限定类名");
获取类的结构:
- java.lang.Class:代表一个类
- java.lang.reflect.Method:代表类的方法
- java.lang.reflect.Field:代表类的成员变量
- java.lang.reflect.Constructor:代表类的构造方法
1
大Class实例.newInstance();//创建对象,默认调用无参构造器
getGenericSuperclass();//在运行时获取带泛型父类的类型。返回值是Type类型。Type :描述所有的类型的类,Type只有一个实现类,Class。
public class ReflectTest {
@Test
public void test() throws InstantiationException, IllegalAccessException {
Class clazz = Person.class;
// 在运行时获取运行时类的实例, newInstance() : 默认调用无参构造器
Person person = clazz.newInstance();
// getFields() : 获取所有 public 修饰的属性,包括父类的
Field[] fields1 = clazz.getFields();
// getDeclaredFields() : 获取所有本类声明的属性,包括私有的,不包括父类的
Field[] fields2 = clazz.getDeclaredFields();
// ########################################################################################
// getMethods() : 获取所有 public 修饰的方法,包括父类的
Method[] methods1 = clazz.getMethods();
// getDeclaredMethods() : 获取本类所有的方法,包括私有的,不包括父类的
Method[] methods2 = clazz.getDeclaredMethods();
// ########################################################################################
// 获取本类所有的构造器,不包括私有的
Constructor[] constructors1 = clazz.getConstructors();
// 获取本类所有的构造器,包括私有的
Constructor[] constructors2 = clazz.getDeclaredConstructors();
// ########################################################################################
// 获取所继承的父类的大class实例
Class super Person> superclass = clazz.getSuperclass();
// ########################################################################################
// 在运行时获取带泛型父类的类型 Type :描述所有的类型的类 参数化类型(带泛型的类型)
Type type = clazz.getGenericSuperclass();
// 在运行时获取带泛型父类的泛型类型 确定参数化类型 获取真实参数
ParameterizedType pt = (ParameterizedType) type;
Type[] types = pt.getActualTypeArguments();
Class c = (Class) types[0];//Type只有一个实现类,Class。
// ########################################################################################
// 在运行时获取运行时类实现的所有接口
Class[] interfaces = clazz.getInterfaces();
// ########################################################################################
// 在运行时获取运行时类的内部类
Class[] classes1 = clazz.getClasses();
Class[] classes2 = clazz.getDeclaredClasses();
// ########################################################################################
// 在运行时获取运行时类的包
Package aPackage = clazz.getPackage();
}
}
获取属性的完整结构
@Test
public void test2() {
Class clazz = Person.class;
// 获取本类所有的属性,包括私有的,不包括父类的
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
// 以整数形式返回此Field的修饰符
System.out.print(Modifier.toString(field.getModifiers())+"t");
// 得到Field的属性类型 返回大Class实例
System.out.print(field.getType().getName()+"t");
// 返回Field的名称
System.out.println(field.getName());
}
}
获取方法的完整结构
public void test2(){
Class clazz = Person.class;
// getMethods() : 获取所有 public 修饰的方法,包括父类的
Method[] methods1 = clazz.getMethods();
// getDeclaredMethods() : 获取本类所有的方法,包括私有的,不包括父类的
Method[] methods2 = clazz.getDeclaredMethods();
for (Method method : methods2) {
//取得修饰符
int i = method.getModifiers();
System.out.print(Modifier.toString(i)+"t");
//取得全部的返回值
Class> type = method.getReturnType();
System.out.print(type+"t");
//取得方法的名称
System.out.print(method.getName()+"(");
//取得全部的参数
Class>[] types = method.getParameterTypes();
for (Class> t : types) {
System.out.print(t+",");
}
System.out.print(")"+"t");
// 取得异常信息
Class>[] classes = method.getExceptionTypes();
for (Class> e : classes) {
System.out.print(e.getName());
}
System.out.println();
}
}
获取构造器的完整结构
Classclazz = Person.class; Constructor>[] constructors = clazz.getDeclaredConstructors(); for (Constructor> constructor : constructors) { //取得构造器修饰符 System.out.print(Modifier.toString(constructor.getModifiers())+"t"); //取得构造器名称 System.out.print(constructor.getName()+"t ("); //取得构造器参数的类型 Class>[] parameterTypes = constructor.getParameterTypes(); for (Class> type : parameterTypes) { System.out.print(type.getName()+","); } System.out.print("){"+"n"); System.out.println("}"); } }
运行时获取并操作运行时类对象的属性【重要】
Field name=clazz.getField("name");//name字段是其他地方获取的,比如从数据库
name.set(o1,o2);为o1对象的name属性值设置为o2
name.get(o1);获取o1对象的name属性
访问私有属性:
age.setAccessible(true);//忽略访问权限,获取私有属性的时候
运行时获取并调用类对象的方法
invoke的返回值是方法m1运行之后的返回值。void则为null
基本数据类型也有对应的大Class实例
getMethod("eat");//方法无参数 则不传参数的Class实例(可变参数0个或多个)
m1.invoke(o1,实参)//调用o1对象的m1方法
补充:
利用反射没有无参构造器怎么创建对象?
1)通过Class类的getDeclaredConstructor(Class … parameterTypes)取得本类的指定形参类型的构造器【一个Constructor对象】
2)调用构造器对象的newInstance(),利用可变参数传递构造器需要的实参,返回值即为根据对应构造器创建的对象
public T newInstance(Object ... initargs){}
反射参考另外一篇文章
2021/11/4 北京 java反射机制,Class对象,Field对象,Method对象_£小羽毛的博客-CSDN博客_java11 反射创建对象



