栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

22-04-29 西安 javaSE(17)泛型与反射

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

22-04-29 西安 javaSE(17)泛型与反射

泛型的引出:

强转可能会出现类型转换异常

【集合中使用泛型】
1、<引用数据类型>,用于限制元素的类型
2、集合中使用泛型,泛型仅仅在编译时有效,在字节码中就没了,叫类型擦除
3.泛型可以放子类的类型。

【不指定泛型,默认Object,可以放任何类型,即任何Object子类都可以】

【自定义泛型类】 T相当于成员变量

什么时候把类定义为自定义泛型类??
     在编译时出现了不确定的数据类型的时候,就用泛型代替。泛型在被应用时指定,被应用指的是创建对象和被继承的时候。

T :Type
E: Element

【自定义泛型方法】
方法出现了不确定类型

public  E myMethod(List list){

//方法返回值类型之前要加,传递的参数是什么类型,返回的就是什么类型

}

通配符:List 

List和List没有子父类继承关系,丧失了多态,会大大降低程序灵活性

List 可以接收任意泛型的集合。但是我们常用的的时候还是要加类型限定的

List可以接收Person本类 或 Person子类类型的集合。不能添加
List 可以接收Person本类 或 Person父类类型的集合,不能遍历,可以添加


以此类推,List和List也没有类继承关系??

泛型其他内容参考我另外一篇文章:

2022/1/4 北京 泛型类,泛型继承,泛型方法_£小羽毛的博客-CSDN博客


反射:动态语言的关键

出现不确定的类型用泛型,出现不确定的对象用反射

返回数据库的一个表结构
public T get(Class clazz){
    //50行查询数据库的代码
    return clazz.newInstance();//出现不确定的类型用泛型,出现不确定的对象用反射
}

反射的功能:
(1)在运行时创建任意类型的对象
(2)在运行时获取任意类型的信息
(3)在运行时获取和设置任意属性值
(4)在运行时调用任意对象的方法

Java的运行状态:

  1. 编译时:javac命令生成class字节码文件(一个.class字节码文件描述一个类)
  2. 运行时: java命令,通过jvm提供的类加载器将.class字节码文件加载到内存中

最最开始的时候__类加载:
每个类的大概内容:【在内存中的类信息】 

  1. This_class/Super_class/Interfaces【层次结构】
  2. Field_info  Method_info  Constroctor  Classes  Annotation【属性表.方法表/构造器/内部类/注解】

类的初始化:

  • 类的加载:创建大Class实例
  • 类的连接:加载静态成员
  • 类的初始化:初始化静态成员

类加载器:加载classpath指定的字节码文件到内存。

  1. 引导类加载器 【获取不了.getParaent()】
  2. 扩展类加载器
  3. 系统类加载器【自定义的类的字节码文件】

双亲委派模型,从最上层,一层一层往下加载【引导类加载器、扩展类加载器、系统类加载器】

    @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 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();
        }
    }

获取构造器的完整结构

      Class clazz = 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 反射创建对象

转载请注明:文章转载自 www.mshxw.com
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号