JavaSE基础篇:反射(二)

简介: JavaSE基础篇:反射(二)


第一章:注解

一:注解引入

Annotation是从jdk5.0引入的技术,注解和反射是很多框架的实现的方式

二:注解作用

不是程序本身:可以对程序作出解释,这一点和注释没有任何区别。

可以被其他程序,例如编译器进行读取,作为一定的标志。

检查和约束,例如:不是正确的重写的方法,上边的@Override就会报错。

三:注解定义格式

@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@interface Fieldkuang{
    String column();
    String type();
    int length();
}

四:注解分类

1:元注解

元注解是解释其他注解的注解,Java当中只有四个元注解 TRDI

@Target:这个注解描述非元注解的使用的位置。这个注解用于描述被修饰注解的使用时放置的位置,非元注解值得就是内置注解和自定义注解,注解所在的包位于,java.lang.annotation包下

@Retention:这个注解描述的是被修饰的注解的生命周期,作用时间分别为source < class< runtime三种情况

@Document:注解表示被修饰的注解被包含在JavaDoc当中

@Inherited:说明子类可以继承父类中被此注解修饰的注解。

2:内置注解

内置注解就是java自带的注解。

@SuppressWarnings(“all”)抑制编译器警告

@Deprecated 表示:某个程序元素(类、方法等)已过时

@SafeVarargs (JDK1.7更新) 表示:专门为抑制“堆污染”警告提供的。

@FunctionalInterface注明这是函数式接口

@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
@Retention(RetentionPolicy.SOURCE)
public @interface SuppressWarnings {
    String[] value();
}

五:自定义注解

自定义注解时,自动继承了java.lang.annotation接口。

@interface用于声明注解,可以public,可以非public,注解中看似像方法的东西其实是一个个参数,方法名就是参数名的名称,获取时采用 注解对象.参数名()进行获取,返回值类型的位置就是参数的类型(基本类型,Class,String,Enum,数组),可以通过default赋值,默认值一般为0或者“”,注解有默认值我们可以不用赋值,注解没有默认值使用的时候必须手动赋值,如果只有一个参数,我们经常叫做value,如果叫做value,赋值的时候可以value = 进行省略,注解可以通过反射机制进行元数据的访问,所以反射+注解的形式会被大量应用在框架中。

//定义一个注解:
//@Target(value = ElementType.METHOD)
//target表示我们的注解可以使用在什么位置
@Target(value = {ElementType.METHOD,ElementType.TYPE})
//retention表示我们的注解什么时候有效,retention默认是runtime
@Retention(value = RetentionPolicy.RUNTIME)
//表示是否将我们的注解保存奥Javadoc当中
@Documented
//表示是否子类是否可以集成父类中的该注解。
@Inherited
@interface MyAnnotation{
    String [] value() default {""};
}

第二章:反射

一:创建对象的四种方式

用new语句创建对象,这是最常用的创建对象的方式

运用反射手段,调用Java.lang.Class或者java.lang.reflect.Constructor类的newInstance()实例方法

调用对象的clone()方法

运用反序列化手段,调用java.io.ObjectInputStream对象的readObject()方法

二:反射机制

1:动态语言

动态语言是运行时可以改变其结构的语言,运行时代码可以根绝某些条件改变自身结构。

2:静态语言

静态语言是指运行时不能改变其代码的自身结构的语言。

反射允许程序在执行期间使用反射的api读取类中的内部信息,并能直接从操作任意对象的内部属性和内部方法。

三:反射可以提供的功能

在运行时判断任意一个对象所属的类,构造任意一个类的对象

运行时获取和调用任意一个类的属性和方法

运行时获取区类中任意位置的泛型信息和注解信息

生成动态代理

四:反射的优缺点

实现动态创建对象和编译,体现出很大的灵活性。

对性能有影响,反射基本上是一种解释性工作,性能较低。

五:反射主要的API

  • java.lang.Class:反射的核心类。
  • java.lang.reflect.Field:类的变量
  • java.lang.reflect.Method:类的方法
  • java.lang.reflect.Constructor:类的构造器
  • java.lang.reflect.ParameterizedType:类的泛型
  • java.lang.annotation.Annotation:类的注解

第三章:Class类和Class对象

一:Class类

Class类是反射中的核心类,这个类是java反射的源头。

二:Class对象

  • 获取java中任何一个类都只有一个Class对象,获取这种Class对象共有五中,包含三种常规方法和两种特有的方法。

三:获取Class对象

1:类名.class

2:对象.getClass()此方法继承自Object

3:Class.forName(“com.yuming.mokuaiming.Name”)

4:内置基本类型数据可以直接用类名.Type

5:还可以使用ClassLoader类加载器

package reflaction;
/**
这个类用于说明,不同方式得到的Class对象是一个。
*/
public class Test02 extends Object {
    public static void main(String[] args) throws ClassNotFoundException {
        //通过反射获取类的class对象
        Class clazz1 = Class.forName("reflaction.User");
        System.out.println(clazz1);//class reflaction.User
        Class clazz2 = Class.forName("reflaction.User");
        Class clazz3 = Class.forName("reflaction.User");
        Class clazz4 = Class.forName("reflaction.User");
        System.out.println(clazz1.hashCode());
        System.out.println(clazz2.hashCode());
        System.out.println(clazz3.hashCode());
        System.out.println(clazz4.hashCode());
//        460141958
//        460141958
//        460141958   一个类在内存中只有一个Class对象,一个类被加载后,整个类的结构都会被封装在这个Class对象当中。
//        460141958   hashcode相同说明是一个类。
    }
}
//实体类,类中只有属性;pojo entity
class User{
    private int id;
    private int age;
    private String name;
    public User(int id, int age, String name) {
        this.id = id;
        this.age = age;
        this.name = name;
    }
    void show(){}
    public User() {
    }
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", age=" + age +
                ", name='" + name + '\'' +
                '}';
    }
}
/**
创建Class对象的五中方式
*/
package reflaction;
public class Test03 {
    public static void main(String[] args) throws ClassNotFoundException {
        Person person = new Student();
        System.out.println("这个人是:"+person.name);
        //方式一:通过对象获得
        Class c1 = person.getClass();
        System.out.println(c1.hashCode());
        //方式二:forName方式获得;
        Class c2 = Class.forName("reflaction.Student");
        System.out.println(c2.hashCode());
        //方式三:通过类名.class可以直接获得。
        Class c3 = Student.class;
        System.out.println(c3.hashCode());
//        这个人是:学生
//        460141958
//        460141958
//        460141958
        //方式四:基本内置类型的包装类都有一个TYPE属性,
        Class c4 = Integer.TYPE;
        System.out.println(c4); //int
        Class c5 = c1.getSuperclass();
        System.out.println(c5);   //class reflaction.Person
    }
}

四:Class对象的细节补充

Class对象只能有系统进行建立

一个加载的类在JVM当中只能有一个Class对象,无论是采用哪种方式获得

一个Class对象对应的是加载到JVM当中的一个Class文件

每个类的实例都会记得自己是由哪个Class实例产生

通过Class对象可以完整的得到一个类中所有被加载的结构细节信息

Class类是反射的根源,动态加载、运行的类都必须获得响应的Class对象

1:JAVA动态加载类和静态加载类的区别

new创建对象的方式称作为静态加载,而使用Class.forName(“XXX”)称作为动态加载,它们俩本质的区别在于静态加载的类的源程序在编译时期加载(必须存在,必须导入类,并且new他的对象)而动态加载的类在编译时期可以缺席(源程序不必存在,写入类的路径就可以骗过编译器)

2:Class类的常用方法

##:3:都有哪些类可以有Class对象

共计七种:

  • Class:Class类本身、外部类、内部类:成员(成员内部类,静态内部类,局部内部类,匿名内部类)
  • interface 接口
  • 数组(一维数组+二维数组)
  • 枚举
  • 注解
  • 基本数据类型
  • Void
package reflaction;
import java.lang.annotation.ElementType;
//所有类型的class对象
public class Test04 {
    public static void main(String[] args) {
        Class c1 = Object.class;//类
        Class c2 = Comparable.class;//接口
        Class c3 = String[].class;//一维数组
        Class c4 = int[][].class;//二维数组
        Class c5 = Override.class;//注解
        Class c6 = ElementType.class;//枚举
        Class c7 = Integer.class;//基本数据类型
        Class c8 = void.class;//void
        Class c9 = Class.class;//Class
        //只要元素的类型和维度是一样的,Class就是一样的。
        int[] a = new int[10];
        int[] b = new int[20];
        System.out.println(a.getClass().hashCode() == b.getClass().hashCode());
//类             System.out.println(c1);      //class java.lang.Object
//接口           System.out.println(c2);      //interface java.lang.Comparable
//一维数组        System.out.println(c3);      //class [Ljava.lang.String;
//二维数组        System.out.println(c4);      //class [[I
//注解           System.out.println(c5);      //interface java.lang.Override
//枚举           System.out.println(c6);      //class java.lang.annotation.ElementType
//基本数据类型    System.out.println(c7);      //class java.lang.Integer
//void           System.out.println(c8);      //void
//Class          System.out.println(c9);      //class java.lang.Class
    }
}

4:反射获取类的运行时结构

创建运行时类的对象,首先需要获取运行时类的结构,这是两个不同的概念。

通过反射获取类运行时的完整的结构包括:

1、 实现的全部的接口。

2、 所继承的父类。

3、 所有的构造器

4、 所有的属性

5、 所有的方法

6、 所有的注解。

动态获取类的构造的对象。

package reflaction;
/**
 * 获取类的信息
 * */
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
//获取类的信息
public class Test08 {//alt + shift + enter --方法上直接抛出异常信息。
    public static void main(String[] args) throws Exception{
        Class c1 = Class.forName("reflaction.User");
        //获取类的名字
        System.out.println(c1.getName());//reflaction.User 这个是全限定类名。
        System.out.println(c1.getSimpleName());//User 这个是单纯的类名。
        //获得类的属性
        //只能获取public修饰的属性
        System.out.println("====================================");
        Field[] fields = c1.getFields();
        //fields.for可以快速实现foreach。
        for (Field field : fields) {
            System.out.println(field);
        }
        //可以获取所有类型的属性
        System.out.println("====================================");
        Field[] fields1 = c1.getDeclaredFields();
        for (Field field : fields1) {
            System.out.println(fields);
//            [Ljava.lang.reflect.Field;@74a14482
//            [Ljava.lang.reflect.Field;@74a14482
//            [Ljava.lang.reflect.Field;@74a14482
        }
        //获取指定名称的属性--只能找到public类型的属性
//        Field field = c1.getField("name");因为找不到这个属性所以会抛出一个NoSuchFieldException,程序碰到异常之后就会停止。
//        System.out.println(field);
        //获取指定名称的属性--可以找到任何类型的属性
        Field field1 = c1.getDeclaredField("name");
        System.out.println(field1);//private java.lang.String reflaction.User.name
        //获取类的方法
        //1、获取所有类的方法--获取本类和父类所有的public修饰的方法
        Method[] methods = c1.getMethods();
        for (Method method : methods) {
            System.out.println(method);
//            public java.lang.String reflaction.User.toString()
//            public java.lang.String reflaction.User.getName()
//            public int reflaction.User.getId()
//            public void reflaction.User.setName(java.lang.String)
//            public void reflaction.User.setId(int)
//            public int reflaction.User.getAge()
//            public void reflaction.User.setAge(int)
//            public final void java.lang.Object.wait() throws java.lang.InterruptedException
//            public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
//            public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
//            public boolean java.lang.Object.equals(java.lang.Object)
//            public native int java.lang.Object.hashCode()
//            public final native java.lang.Class java.lang.Object.getClass()
//            public final native void java.lang.Object.notify()
//            public final native void java.lang.Object.notifyAll()
            //2、获取本类的所有的public和非public的方法
            System.out.println("=============================================");
            Method[] methods1 = c1.getDeclaredMethods();
            for (Method method1 : methods1) {
                System.out.println(method1);
//                public java.lang.String reflaction.User.toString()
//                public java.lang.String reflaction.User.getName()
//                public int reflaction.User.getId()
//                public void reflaction.User.setName(java.lang.String)
//                public void reflaction.User.setId(int)
//                void reflaction.User.show()
//                public void reflaction.User.setAge(int)
//                public int reflaction.User.getAge()
            }
            //3、获取指定方法
            Method method1 = c1.getMethod("getName",null);
            Method method2 = c1.getMethod("setName",String.class);
//            System.out.println(method1);public java.lang.String reflaction.User.getName()
//            System.out.println(method2);public void reflaction.User.setName(java.lang.String)
            //获取构造器
            //1、获取本类的所有的public的构造器
            System.out.println("==============================================");
            Constructor[] constructors = c1.getConstructors();
            for (Constructor constructor : constructors) {
                System.out.println(constructor);
//                public reflaction.User(int,int,java.lang.String)
//                public reflaction.User()
            }
            //2、获取本类的所有的public和非public的构造器
            System.out.println("==============================================");
            Constructor[] constructor1 = c1.getDeclaredConstructors();
            for (Constructor constructor : constructor1) {
                System.out.println(constructor);
//                public reflaction.User(int,int,java.lang.String)
//                public reflaction.User()
            }
            //3、获取指定名称的构造器
            System.out.println("===============================================");
            Constructor constructor = c1.getConstructor(int.class,int.class,String.class);
            System.out.println(constructor);
            constructor = c1.getConstructor(Integer.TYPE,Integer.TYPE,"".getClass());
            System.out.println(constructor);
            constructor = c1.getConstructor(Integer.TYPE,Integer.TYPE,Class.forName("java.lang.String"));
            System.out.println(constructor);
            constructor = c1.getDeclaredConstructor(Integer.TYPE,Integer.TYPE,"".getClass());
            System.out.println(constructor);
            constructor = c1.getDeclaredConstructor(Integer.TYPE,Integer.TYPE,Class.forName("java.lang.String"));
            System.out.println(constructor);
//            public reflaction.User(int,int,java.lang.String)
//            public reflaction.User(int,int,java.lang.String)
//            public reflaction.User(int,int,java.lang.String)
//            public reflaction.User(int,int,java.lang.String)
//            public reflaction.User(int,int,java.lang.String)
        }
    }
}
package reflaction;
/**
 * 动态获取类运行时结构的对象
 * */
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
//动态的创建类的运行时结构对象
public class Test09 {
    public static void main(String[] args) throws Exception {
        //获得User的Class对象
        Class c1 = Class.forName("reflaction.User");
        //创建一个User对象
        //本质上是调用了类的无参构造器。--如果没有无参构造器,就会报错。
//        User user = (User)c1.newInstance();
//        System.out.println(user);
        //通过构造器对象如何创建对象
//        Constructor constructor = c1.getConstructor(String.class, int.class, int.class);
        Constructor constructor = c1.getConstructor(int.class, int.class, String.class); //参数的个数、类型、顺序必须实际构造器保持一致。
        User user1 =(User)constructor.newInstance(001,10,"秦江");
        System.out.println(user1);
        //通过反射调用普通方法
        User user3 = (User)c1.newInstance();
        //获取指定名称的方法
        Method setName = c1.getDeclaredMethod("setName", String.class);
        //激活方法执行方法--invoke(谁的方法,方法的参数) 返回值是原方法的返回值,原方法没有则返回null
        setName.invoke(user3, "kuangshen");
        System.out.println(user3);
        System.out.println(user3.getName());//kuangshen
        //通过方法调用属性
        User user4 = (User)c1.newInstance();
        Field field = c1.getDeclaredField("name");
        /**
         * 不能直接操作私有属性,我们需要关闭程序的安全检测,属性或者方法的setAccessble方法。
         * */
        field.setAccessible(true);//这样就不检查属性是否是private了。默认是FALSE
        field.set(user4,"狂神2"); //Class reflaction.Test09 can not access a member of class reflaction.User with modifiers "private"
        System.out.println(user4.getName());//狂神2
    }
}

4:关闭私有检查的效率问题

package reflaction;
import java.lang.reflect.Method;
//比较性能问题
public class Test10 {
    public static void main(String[] args) throws Exception {
        //普通方式
        test01();
        test02();
        test03();
//        普通方式执行10亿次:0ms
//        反射不关闭执行10亿次:2437ms
//        反射关闭私有检查执行10亿次:1109ms 关闭之后效率提升了两到三倍。
    }
    private static void test01(){
        User user = new User();
        long startTime = System.currentTimeMillis();
        for (int i = 0; i < 1000000000; i++) {
            user.getName();
        }
        long endTime = System.currentTimeMillis();
        System.out.println("普通方式执行10亿次:"+(endTime - startTime)+"ms");//普通方式执行10亿次:10ms
    }
    private static void test02() throws Exception {
        Class c1 = Class.forName("reflaction.User");
        User user = new User();
        Method method = c1.getMethod("getName",null);
        long startTime = System.currentTimeMillis();
        for (int i = 0; i < 1000000000; i++) {
            method.invoke(user);
        }
        long endTime = System.currentTimeMillis();
        System.out.println("反射不关闭执行10亿次:"+(endTime - startTime)+"ms");//普通方式执行10亿次:2347ms
    }
    private static void test03() throws Exception {
        Class c1 = Class.forName("reflaction.User");
        User user = new User();
        Method method = c1.getMethod("getName",null);
        method.setAccessible(true);
        long startTime = System.currentTimeMillis();
        for (int i = 0; i < 1000000000; i++) {
            method.invoke(user);
        }
        long endTime = System.currentTimeMillis();
        System.out.println("反射关闭执行10亿次:"+(endTime - startTime)+"ms");//普通方式执行10亿次:1206ms
    }
}

5:反射构建类运行时结构对象-泛型

package reflaction;
import sun.reflect.generics.tree.ReturnType;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Map;
//通过反射获取泛型
public class Test11 {
    public void test01(Map<String,User> map, List<User> list){
        System.out.println("test01");
    }
    public Map<String,User> test02(){
        System.out.println("test02");
        return null;
    }
    public static void main(String[] args) throws Exception {
        Method method = Test11.class.getMethod("test01",Map.class,List.class);
        //获取带有泛型的参数类型
        Type[] genericParameterTypes = method.getGenericParameterTypes();
        for (Type genericParameterType : genericParameterTypes) {
            System.out.println(genericParameterType);//例如:java.util.Map<java.lang.String, reflaction.User>
            if(genericParameterType instanceof ParameterizedType){
                //获取带有泛型的参数类型中的真实泛型类型
                Type[] actualTypeArguments = ((ParameterizedType) genericParameterType).getActualTypeArguments();
                for (Type actualTypeArgument : actualTypeArguments) {
                    System.out.println(actualTypeArgument.getTypeName());//例如:java.lang.String,,reflaction.User
                }
            }
        }
//        java.util.Map<java.lang.String, reflaction.User>
//        java.lang.String
//        reflaction.User
//        java.util.List<reflaction.User>
//        reflaction.User
        System.out.println("===========================================================");
        Method test02 = Test11.class.getMethod("test02",null);
        Type genericReturnType = test02.getGenericReturnType();
        if(genericReturnType instanceof ParameterizedType){
            System.out.println(genericReturnType.getTypeName());
            Type[] actualTypeArguments = ((ParameterizedType) genericReturnType).getActualTypeArguments();
            for (Type actualTypeArgument : actualTypeArguments) {
                System.out.println(actualTypeArgument.getTypeName());//例如:java.lang.String,,reflaction.User
            }
        }
    }
}

6:反射获取类运行时结构对象-注解

package reflaction;
//练习反射操作注解。
/*
 * 通过反射操作注解,我们以后用到的框架当中都是这样写的,
 * 他们在类中会有大量的注解,通过反射读取这个注解,进行
 * 响应的操作。
 */
import java.lang.annotation.*;
import java.lang.reflect.Field;
public class Test12 {
    public static void main(String[] args) throws Exception {
        Class c1 = Class.forName("reflaction.Student2");
        //通过反射获取注解
        Annotation[] annotations = c1.getAnnotations();
        for (Annotation annotation : annotations) {
            System.out.println(annotation); //@reflaction.Tablekuang(value=db_student)
        }
        //获取注解value的值
        Tablekuang annotation = (Tablekuang)c1.getAnnotation(Tablekuang.class);
        String value  = annotation.value();
        System.out.println(value);//db_student
        //获得类指定的注解
        Field name = c1.getDeclaredField("name");
        Fieldkuang fieldkuang = name.getAnnotation(Fieldkuang.class);
        System.out.println(fieldkuang.column());    //        db_id
        System.out.println(fieldkuang.type());      //        varchar
        System.out.println(fieldkuang.length());    //        10
    }
}
@Tablekuang("db_student")
class Student2{
    @Fieldkuang(column = "db_id",type = "int",length = 10)
    private int id;
    @Fieldkuang(column = "db_id",type = "int",length = 10)
    private int age;
    @Fieldkuang(column = "db_id",type = "varchar",length = 10)
    private String name;
    public Student2(){
    }
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    @Override
    public String toString() {
        return "Student2{" +
                "id=" + id +
                ", age=" + age +
                ", name='" + name + '\'' +
                '}';
    }
}
@SuppressWarnings("all")
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@interface Tablekuang{
    String value() ;
}
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@interface Fieldkuang{
    String column();
    String type();
    int length();
}

类加载和类加载器

相关文章
|
4月前
|
存储 Java 编译器
JavaSE基础:类和接口
JavaSE基础:类和接口
|
XML 安全 Java
【javaSE】 反射与反射的使用
【javaSE】 反射与反射的使用
|
6月前
|
存储 设计模式 安全
JavaSE基础篇:反射(一)
JavaSE基础篇:反射(一)
JavaSE基础篇:反射(一)
|
6月前
|
缓存 安全 前端开发
【JavaSE】反射与模块化
【JavaSE】反射与模块化
70 0
|
存储 SpringCloudAlibaba 安全
JavaSE高级特性:反射
Java反射是框架的灵魂,大量框架底层都用到了反射机制,例如Spring.... Java反射是在**运行状态时**,可以构造任何一个类的对象,获取到任意一个对象所属的类信息,以及这个类的成员变量或者方法,可以调用任意一个对象的属性或者方法。可以理解为具备了**动态加载对象**以及**对对象的基本信息进行剖析和使用**的能力的一种机制。
117 0
JavaSE高级特性:反射
|
移动开发 Java 网络安全
【java】反射基础
【java】反射基础
56 0
|
Java
Java 反射--获取类的内部结构详解
Java 反射--获取类的内部结构详解
42 0
|
JavaScript 前端开发 Java
【JavaSE】之注解与反射(上)
【JavaSE】之注解与反射(上)
【JavaSE】之注解与反射(上)
|
缓存 安全 前端开发
【JavaSE】之注解与反射(下)
【JavaSE】之注解与反射(下)
【JavaSE】之注解与反射(下)