Java高级编程–反射–day09

知识点和问题

        • 1.动态语言vs静态语言
        • 2.反射机制能实现哪些功能?
        • 3.反射相关的API有哪些?
        • 4.通过直接new的方式或反射的方式都可以调用公共的结构,开发中到底用哪个?
        • 5.反射机制与面向对象中的封装性是不是矛盾?如何看到两个技术?
        • 6.类的加载?
        • 7.获取Class的实例有几种方式?
        • 8.判断如下程序的运行结果是什么?
        • 9.哪些类型可以有Class对象?
        • 10.类的加载实例代码如下
        • 11.类的加载
        • 12.ClassLoader的理解
        • 13.样例代码获取类加载器
        • 14.使用ClassLoader加载配置文件
        • 15.通过反射创建对应的运行时类的对象
        • 16.反射的动态性示例代码
        • 17.获取运行运行时类的属性结构
        • 18.获取权限修饰符 数据类型 变量名
        • 19.获取运行时类的方法结构
        • 20.获取运行时类方法的内部结构
        • 21.获取运行时类的构造器结构
        • 22.获取运行时的父类
        • 23.获取运行时带泛型的父类
        • 24.获取运行时类的带泛型的父类的泛型
        • 25.获取运行时类的接口
        • 26.获取运行时类所在的包
        • 27.获取运行时类声明的注解
        • 28.获取处理时类指定的属性
        • 29.如何操作运行时类中的指定的方法
        • 30.调用运行时类中的指定的构造器

1.动态语言vs静态语言

1.动态语言:运行时代码可以根据某些条件改变自身结构。
2.静态语言:运行时结构不变的语言就是静态语言。java不是动态语言,是"准动态语言",因为Java提供了反射机制。

2.反射机制能实现哪些功能?

在运行时判断任意一个对象所属的类
在运行时构造任意一个类的对象
在运行时判断任意一个类所具有的成员变量和方法
在运行时获取泛型信息
在运行时调用任意一个对象的成员变量和方法
在运行时处理注解
生成动态代理

3.反射相关的API有哪些?

1.java.lang.Class:代表一个类
2.java.lang.reflect.Method:代表类的方法
3.java.lang.reflect.Field:代表类的成员变量
4.java.lang.reflect.Constructor:代表类的构造器

4.通过直接new的方式或反射的方式都可以调用公共的结构,开发中到底用哪个?

一般采用直接new的方式,当需要进行动态反射的时候使用反射机制。

5.反射机制与面向对象中的封装性是不是矛盾?如何看到两个技术?

不矛盾。封装新解决的是访问权限问题,反射解决的是调用类的问题 。

6.类的加载?

1.类的加载过程:
程序经过javac.exe命令以后,会生成一个或多个字节码文件(.class结尾)。接着我们使用java.exe命令对某个字节码文件进行解释运行。相当于将某个字节码文件加载到内存中。此过程就称为类的加载。加载到内存中的类,我们就称为运行时类,此运行时类,就作为Class的一个实例。
Java高级编程–反射–day09_第1张图片
2.换句话说,Class的实例就对应着一个运行时类。
3.加载到内存中的运行时类,会缓存一定的时间。在此时间之内,我们可以通过不同的方式来获取此运行时类。

7.获取Class的实例有几种方式?

有四种,实例代码如下:

public class ReflectionTest {
    @Test
    public void test() throws ClassNotFoundException {
        //调用运行时类的属性:.class
        Class clazz1=Person.class;
        System.out.println(clazz1);
        //通过运行时类的对象调用getClass()
        Person p1=new Person();
        Class clazz2=p1.getClass();
        System.out.println(clazz2);
        //调用Class的静态方法:
        Class clazz3=Class.forName("com.atguigu.java1.Person");
        System.out.println(clazz3);
        //使用类的加载器:ClassLoader
        ClassLoader classLoader=ReflectionTest.class.getClassLoader();
        Class clazz4=classLoader.loadClass("com.atguigu.java.Person");
        System.out.println(clazz4);
    }
}

8.判断如下程序的运行结果是什么?

   @Test
    public void test1(){
        int[] a=new int[10];
        int[] b=new int[100];
        Class c10=a.getClass();
        Class c11=b.getClass();
        System.out.println(c10==c11);
    }

运行结果:
true
原因:只要数组的元素类型与维度一样,就是同一个Class

9.哪些类型可以有Class对象?

(1)class:
外部类,成员(成员内部类,静态内部类),局部内部类,匿名内部类
(2)interface:接口
(3)[]:数组
(4)enum:枚举
(5)annotation:注解@interface
(6)primitive type:基本数据类型
(7)void
样例代码如下:
Class c1 = Object.class;
Class c2 = Comparable.class;
Class c3 = String[].class;
Class c4 = int[][].class;
Class c5 = ElementType.class;
Class c6 = Override.class;
Class c7 = int.class;
Class c8 = void.class;
Class c9 = Class.class;

10.类的加载实例代码如下

public class ClassLoadingTest {
public static void main(String[] args) {
System.out.println(A.m);
}
}
class A {
static {
m = 300;
}
static int m = 100;
}
//第二步:链接结束后m=0
//第三步:初始化后,m的值由()方法执行决定
// 这个A的类构造器()方法由类变量的赋值和静态代码块中的语句按照顺序合并
产生,类似于
// (){
// m = 300;
// m = 100;
// }

11.类的加载

Java高级编程–反射–day09_第2张图片
类加载器的作用:
1.类加载的作用:将class文件字节码内容加载到内存中,并将这些静态数据转换成方法区的运行时数据结构,然后在堆中生成一个代表这个类的java.lang.Class对象,作为方法区中类数据的访问入口。
2.类缓存:标准的JavaSE类加载器可以按要求查找类,但一旦某个类被加载到类加载器中,它将维持加载(缓存)一段时间。不过JVM垃圾回收机制可以回收这些Class对象。

12.ClassLoader的理解

类加载器作用是用来把类(class)装载进内存的。JVM 规范定义了如下类型的类的加载器。
Java高级编程–反射–day09_第3张图片

13.样例代码获取类加载器

@Test
public void test2(){
    //获取系统加载器
    ClassLoader classLoader=ReflectionTest.class.getClassLoader();
    System.out.println(classLoader);
    //获取扩展类加载器
    ClassLoader classLoader1=classLoader.getParent();
    System.out.println(classLoader1);
    //无法获取引导加载器,引导类加载器主要负责加载java的核心类库,无法加载自定义类的
    ClassLoader classLoader2=classLoader1.getParent();
    System.out.println(classLoader2);
    ClassLoader classLoader3=String.class.getClassLoader();
    System.out.println(classLoader3);
}

14.使用ClassLoader加载配置文件

使用方式一读取

public void test3() throws IOException {
    Properties pros=new Properties();
    FileInputStream fis=new FileInputStream("jdbc.properties");
    pros.load(fis);
    String user=pros.getProperty("user");
    String password=pros.getProperty("password");
    System.out.println("user="+user+",password="+password);
}

使用方式二读取

@Test
public void test4() throws IOException {
    Properties pros=new Properties();
    ClassLoader classLoader=ReflectionTest.class.getClassLoader();
    InputStream is=classLoader.getResourceAsStream("jdbc.properties");//目录和方法一的路径位置有出入
    pros.load(is);
    String user=pros.getProperty("user");
    String password=pros.getProperty("password");
    System.out.println("user="+user+",password="+password);
}

15.通过反射创建对应的运行时类的对象

1.使用newInstance方法创建,示例代码如下:

   @Test
    public void test5() throws IllegalAccessException, InstantiationException {
        Class<Person> clazz=Person.class;
        Person obj=clazz.newInstance();
        System.out.println(obj);
    }

说明:
调用方法newInstance创建运行时类的对象,要求:
1.运行时类必须提供空参的构造器
2.空参的构造器的访问权限必须够,通常,设置为public
在javabean中要求提供一个public的空参构造器,原因
1.便于通过反射,创建运行时类的对象
2.便于子类继承此运行时类时,默认调用super()时,保证父类由此构造器

16.反射的动态性示例代码

@Test
public void test6() throws IllegalAccessException, InstantiationException, ClassNotFoundException {
    int num=new Random().nextInt(3);
    String classPath="";
    switch(num){
        case 0:
            classPath="java.util.Date";
            break;
        case 1:
            classPath="com.atguigu.java1.Person";
            break;
    }
    Object obj=getInstance(classPath);
    System.out.println(obj);
}
public Object getInstance(String classPath) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
    Class clazz=Class.forName(classPath);
    return clazz.newInstance();
}

17.获取运行运行时类的属性结构

样例代码:

public class Creature<T> implements Serializable {
    private char gender;
    public double weight;
    private void breath(){
        System.out.println("生物呼吸");
    }
    public void eat(){
        System.out.println("生物吃东西");
    }
}
public interface MyInterface {
    void info();
}
@Target({TYPE,FIELD,METHOD,PARAMETER,CONSTRUCTOR,LOCAL_VARIABLE})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
    String value() default  "hello";
}
@MyAnnotation(value="hi")
public class Person extends Creature<String> implements  Comparable<String>,MyInterface{
   private String name;
   int age;
   public int id;
   public Person(){}
   @MyAnnotation(value="abc")
   private Person(String name){
       this.name=name;
   }
   Person(String name,int age){
       this.name=name;
       this.age=age;
   }
   @MyAnnotation
   private String show(String nation){
       System.out.println("我的国籍是:"+nation);
       return nation;
   }
   public String display(String interets){
       return interets;
   }
    @Override
    public int compareTo(String s) {
        return 0;
    }
    @Override
    public void info() {
        System.out.println("我是一个人");
    }
}
public class FieldTest {
    @Test
    public void test(){
        Class clazz= Person.class;
        Field[] fields=clazz.getFields();
        for(Field f:fields){
            System.out.println(f);
        }
  System.out.println();
        Field[] declaredFields=clazz.getDeclaredFields();
        for(Field f:declaredFields){
            System.out.println(f);
        }
    }
}

运行结果:
public int com.atguigu.java.Person.id
public double com.atguigu.java.Creature.weight

private java.lang.String com.atguigu.java.Person.name
int com.atguigu.java.Person.age
public int com.atguigu.java.Person.id
结论1:
getFields()方法是获取当前运行时类及其父类中声明为public访问权限的属性
getDeclaredFields():获取当前运行时类中声明的所有属性。(不包含父类中声明的属性)

18.获取权限修饰符 数据类型 变量名

@Test
public void test2(){
    Class clazz=Person.class;
    Field[] declaredFields=clazz.getDeclaredFields();
    for(Field f:declaredFields){
        int modifier=f.getModifiers();
        System.out.println(Modifier.toString(modifier)+"\t");
        Class type=f.getType();
        System.out.println(type.getName()+"\t");
        String fName=f.getName();
        System.out.println(fName);
    }
}

19.获取运行时类的方法结构

  @Test
   public void test1(){
       Class clazz= Person.class;
       Method[] methods=clazz.getMethods();
       for(Method m:methods){
           System.out.println(m);
       }
       System.out.println();
       Method[] declaredMethods=clazz.getDeclaredMethods();
       for(Method m:declaredMethods){
           System.out.println(m);
       }
   }

结论:
getMethods():获取当前运行时类及所有父类中声明为public权限的方法
getDeclaredMethods():获取当前运行时类中声明的所有方法(不包含父类中声明的方法)

20.获取运行时类方法的内部结构

@Test
public void test2(){
    Class clazz=Person.class;
    Method[] declaredMethods=clazz.getDeclaredMethods();
    for(Method m:declaredMethods){
        Annotation[] annos=m.getAnnotations();
        for(Annotation a:annos){
            System.out.println(a);
        }
        System.out.print(Modifier.toString(m.getModifiers())+"\t");
        System.out.print(m.getReturnType().getName()+"\t");
        System.out.print(m.getName());
        System.out.print("(");
        Class[] parameterType=m.getParameterTypes();
        if(!(parameterType==null&&parameterType.length==0)){
            for(int i=0;i<parameterType.length;i++){
                if(i==parameterType.length-1){
                    System.out.print(parameterType[i].getName()+"args_"+i);
                    break;
                }
                System.out.print(parameterType[i].getName()+"args_"+i+",");
            }
        }
        System.out.print(")");
        Class[] exceptionTypes=m.getExceptionTypes();
        if(exceptionTypes.length>0){
            System.out.println("throws");
            for(int i=0;i<exceptionTypes.length;i++){
                if(i==exceptionTypes.length-1){
                    System.out.print(exceptionTypes[i].getName());
                }
                System.out.print(exceptionTypes[i].getName()+",");
            }
        }
        System.out.println();
    }
}

21.获取运行时类的构造器结构

  @Test
   public void test3(){
       Class clazz=Person.class;
       Constructor[] constructors=clazz.getConstructors();
       for(Constructor c:constructors){
           System.out.println(c);
       }
       System.out.println();
       Constructor[] declaredConstructors=clazz.getDeclaredConstructors();
       for(Constructor c:constructors){
           System.out.println(c);
       }
   }

1.getConstructors():获取当前运行时类中声明为public的构造器
2.getDeclaredConstructors():获取当前运行时类中声明的所有构造器(不包括父类中的构造器)

22.获取运行时的父类

public void test4(){
    Class clazz=Person.class;
    Class superclass=clazz.getSuperclass();
    System.out.println(superclass);
}

运行结果:
class com.atguigu.java.Creature

23.获取运行时带泛型的父类

@Test
public void test5(){
    Class clazz=Person.class;
    Type genericSuperclass=clazz.getGenericSuperclass();
    System.out.println(genericSuperclass);
}

运行结果:
com.atguigu.java.Creature

24.获取运行时类的带泛型的父类的泛型

@Test
public void test6(){
    Class clazz=Person.class;
    Type genericSuperclass=clazz.getGenericSuperclass();
    ParameterizedType paramType=(ParameterizedType)genericSuperclass;
    Type[] actualTypeArguments=paramType.getActualTypeArguments();
    System.out.println(((Class)actualTypeArguments[0]).getName());
}

25.获取运行时类的接口

@Test
public void test7(){
    Class clazz=Person.class;
    Class[] interfaces=clazz.getInterfaces();
    for(Class c:interfaces){
        System.out.println(c);
    }
}

运行结果:
interface java.lang.Comparable
interface com.atguigu.java.MyInterface

26.获取运行时类所在的包

@Test
public void test8(){
    Class clazz=Person.class;
    Package pak=clazz.getPackage();
    System.out.println(pak);
}

运行结果:
package com.atguigu.java

27.获取运行时类声明的注解

@Test
public void test9(){
    Class clazz=Person.class;
    Annotation[] annotations=clazz.getAnnotations();
    for(Annotation annos:annotations){
        System.out.println(annos);   
    }
}

运行结果:@com.atguigu.java.MyAnnotation(value=“hi”)

28.获取处理时类指定的属性

public void test10() throws IllegalAccessException, InstantiationException, NoSuchFieldException {
    Class clazz=Person.class;
    Person p=(Person) clazz.newInstance();
    //获取指定的属性:要求运行时类中属性声明为public
    Field id=clazz.getField("id");
    id.set(p,1001);
    int pId=(int)id.get(p);
    System.out.println(pId);
}
@Test
public void test11() throws IllegalAccessException, InstantiationException, NoSuchFieldException {
    Class clazz=Person.class;
    Person p=(Person)clazz.newInstance();
    Field name=clazz.getDeclaredField("name");
    name.setAccessible(true);
    name.set(p,"Tom");
    System.out.println(name.get(p));
}

29.如何操作运行时类中的指定的方法

@Test
public void test12() throws Exception {
    Class clazz=Person.class;
    Person p=(Person)clazz.newInstance();
    Method show=clazz.getDeclaredMethod("show",String.class);
    show.setAccessible(true);
    Object returnValue=show.invoke(p,"CHN");
    System.out.println("调用静态方法");
    Method showDesc=clazz.getDeclaredMethod("showDesc");
    showDesc.setAccessible(true);
    //如果调用的运行时类中的方法没有返回值,则此invoke()返回null
    Object returnVal=showDesc.invoke(Person.class);
    System.out.println(returnVal);
}

30.调用运行时类中的指定的构造器

   @Test
    public void test13() throws Exception {
        Class clazz=Person.class;
        Constructor constructor=clazz.getDeclaredConstructor(String.class);
        constructor.setAccessible(true);
        Person per=(Person)constructor.newInstance("Tom");
        System.out.println(per);
    }

你可能感兴趣的:(Java高级编程–反射–day09)