Java基础day25 ——反射

1.JDK1.7以后的try-catch新格式

不需要处理关闭流的操作

package com.atguigu.java;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;

/*
    JDK1.7以后try-catch的新格式
 */
public class TryCatchTest {
    public static void main(String[] args) {

        /*
        FileInputStream fis = null;
        try {
            fis = new FileInputStream("a.txt");
            int i = fis.read();
            System.out.println(i);
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            try {
                if (fis != null) {
                    fis.close();
                }
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
         */

        try(
            //创建的流对象 --- 不需要去处理关闭流的操作了
            // (正常执行还是出现异常都会在最后(try-catch结束)的时候)关闭资源
            FileInputStream fis = new FileInputStream("a.txt");
         ){
            int i = fis.read();
            System.out.println(i);
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}

2.获取Class对象的四种方式

方式:类名.class、对象名.getClass、Class.forName(“全类名”)- 最多-更灵活

package com.atguigu.java4;

import org.junit.Test;

/*
    获取Class对象的四种方式
 */
public class ClassTest {

    @Test
    public void test() throws ClassNotFoundException {
        Person p = new Person();

        //方式一:类名.class
        Class clazz = Person.class;

        //方式二:对象名.getClass();
        Class clazz2 = p.getClass();

        //方式三 :Class.forName("全类名") - 最多 - 更灵活
        Class clazz3 = Class.forName("com.atguigu.java4.Person");

        //方式四 :类加载器.loadClass("全类名") - 了解
        ClassLoader classLoader = this.getClass().getClassLoader();
        Class clazz4 = classLoader.loadClass("com.atguigu.java4.Person");


        System.out.println(clazz == clazz2 && clazz3 == clazz4);
    }

    @Test
    public void test2() throws ClassNotFoundException {
        //在调用方法时一定传一个必须存在的类
        //通过流读取配置文件 --- 配置文件中的内容修改是不会影响代码本身
        String s = "读取配置文件";
        set(s);
    }

    /*
        通用模板 : 要求设计一个方法给某一个类创建对象并给所有属性赋值
     */
    public void set(String s) throws ClassNotFoundException {
        //创建对象并给所有属性赋值
        Class clazz = Class.forName(s);
        //创建对象
    }

}

3.通过反射可以获取类中的所有结构

给私有属性赋值  、 调用私有方法、 获取构造器 创建对象

package com.atguigu.java4;



import java.lang.reflect.Field;
import java.lang.reflect.Method;

/*
    通过反射可以获取类中所有的结构
 */
public class ReflectTest {
    public static void main(String[] args) throws Exception {

        Person p = new Person();

        //通过反射 - 给私有属性赋值
        Class clazz = p.getClass();
        Field id = clazz.getDeclaredField("id");
        id.setAccessible(true);
        id.set(p,20);

        p.show();


        //通过反射 - 调用私有方法
        Method method = clazz.getDeclaredMethod("say");
        method.setAccessible(true);
        method.invoke(p);//调用了私有方法


        //通过反射 获取私有构造器 创建对象

    }
}

4.通过反射获得属性—— 获取所以属性

可以获取所有属性 和 获取指定的属性 

package com.atguigu.java5;

import org.junit.Test;

import java.lang.reflect.Field;

public class ReflectTest {
    /*
        通过反射获取属性 - 获取所有属性
     */
    @Test
    public void test(){
        //获取Class对象
        Class clazz = Student.class;
        //获取属性---获取的是本类及父类中所有public修饰的属性
        Field[] fields = clazz.getFields();
        //遍历
        for (Field field : fields) {
            System.out.println(field);
        }

        System.out.println("===============================================");

        //获取本类中所有属性
        Field[] declaredFields = clazz.getDeclaredFields();
        //遍历
        for (Field declaredField : declaredFields) {
            System.out.println(declaredField);
        }
    }

    /*
        通过反射获取属性 - 获取指定的属性
     */
    @Test
    public void test2() throws Exception {
        Student s = new Student();

        //1.获取Class对象
        Class clazz = Student.class;
        //2.获取指定属性 - public修饰的
        Field sidPublic = clazz.getField("sidPublic");
        //给属性赋值
        /*
        set(Object obj, Object value)
        obj : 给哪个对象中的该属性赋值
        value : 赋值的内容
         */
        sidPublic.set(s,20);//给s对象中的sidPublic赋值

        s.studentShow();
    }

    /*
     通过反射获取属性 - 获取指定的属性
  */
    @Test
    public void test3() throws Exception {
        Student s = new Student();

        //1.获取Class对象
        Class clazz = Student.class;
        //2.获取指定属性 - 可以获取任意权限修饰符修饰的属性
        Field sidPrivate = clazz.getDeclaredField("sidPrivate");
        //授权 - 允许访问
        sidPrivate.setAccessible(true);
        //给属性赋值
        /*
        set(Object obj, Object value)
        obj : 给哪个对象中的该属性赋值
        value : 赋值的内容
         */
        sidPrivate.set(s,30);//给s对象中的sidPrivate赋值

        s.studentShow();
    }


}

5.通过反射获取方法

获取所有的方法 和指定的方法 methods  和stestPublic

package com.atguigu.java5;

import org.junit.Test;

import java.lang.reflect.Method;

public class ReflectTest2 {
     /*
        通过反射获取方法 - 获取所有的
     */
    @Test
    public void test(){
        //1.获取Class对象
        Class clazz = Student.class;
        //2.获取方法-获取本类及父类中所有public修饰的方法
        Method[] methods = clazz.getMethods();
        //3.遍历
        for (Method method : methods) {
            System.out.println(method);
        }

        System.out.println("======================================");
        //获取本类中所有的方法
        Method[] declaredMethods = clazz.getDeclaredMethods();
        //遍历
        for (Method declaredMethod : declaredMethods) {
            System.out.println(declaredMethod);
        }
    }
    /*
        通过反射获取方法 - 获取指定的方法
     */
    @Test
    public void test2() throws Exception {
        Student s = new Student();

        //1.获Class对象
        Class clazz = Student.class;
        //2.获取指定的方法 - public修饰的方法
        Method stestPublic = clazz.getMethod("stestPublic");
        //3.调用方法
        /*
            invoke(Object obj, Object... args)
            obj : 对象名-通过哪个对象调用该方法
            args : 实参
         */
        stestPublic.invoke(s);

        System.out.println("======================================");
        //获取指定的方法- public修饰的方法
        /*
        getMethod(String name, Class<?>... parameterTypes)
        name : 方法的名字
        parameterTypes : 形参类型的运行时类
         */
        Method sdemoPublic = clazz.getMethod("sdemoPublic", String.class,int.class);
        //调用方法
         /*
            invoke(Object obj, Object... args)
            obj : 对象名-通过哪个对象调用该方法
            args : 实参
         */
        sdemoPublic.invoke(s,"xiaolongge",30);

    }

    @Test
    public void test3() throws Exception {
        Student s = new Student();

        //1.获取Class对象
        Class clazz = Student.class;
        //2.获取指定的方法 - 任意权限修饰符修饰的方法
        Method declaredMethod = clazz.getDeclaredMethod("srunPrivate");
        //3.授权-允许访问
        declaredMethod.setAccessible(true);
        //4.调用方法
        declaredMethod.invoke(s);
    }



}

6.通过反射获取构造器

获取构造器和没有获取构造器直接造对象

package com.atguigu.java5;

import org.junit.Test;

import java.lang.reflect.Constructor;

public class ReflectTest3 {
     /*
        通过反射获取构造器
     */
    @Test
    public void test() throws Exception {
        Class clazz = Employee.class;
        //获取构造器
        /*
        getDeclaredConstructor(Class<?>... parameterTypes) :获取指定构造器(任意权限修饰符修饰的)
        parameterTypes : 形参的类型
         */
        Constructor declaredConstructor = clazz.getDeclaredConstructor(int.class);
        //授权
        declaredConstructor.setAccessible(true);
        //创建对象
        /*
        newInstance(Object ... initargs) : 创建对象
        initargs :实参
         */
        Employee e = (Employee) declaredConstructor.newInstance(20);
    }



    /*
        通过反射创建对象 :没有获取构造器直接造对象
     */
    @Test
    public void test2() throws InstantiationException, IllegalAccessException {
        Class clazz = Employee.class;
        //直接通过空参构造器造对象 --- 如果该类没有空参构造器就不能这样子造对象(需要先获取构造器再造对象)
        clazz.newInstance();
    }


    /*
        通过反射获取父类,接口
     */
    @Test
    public void test3(){
        Class clazz = Employee.class;

        //获取父类 -- 有了父类就可以获取父类中的方法 属性 构造器 父类的父类
        Class superclass = clazz.getSuperclass();
        System.out.println(superclass);

        //获取接口
        Class[] interfaces = clazz.getInterfaces();
        for (Class anInterface : interfaces) {
            System.out.println(anInterface);
        }

    }
}

7.获取属性的详细信息

package com.atguigu.java5;

import org.junit.Test;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;

public class ReflectTest4 {
    /*
        获取属性的详细信息
     */
    @Test
    public void test(){
        Class clazz = Dog.class;
        //获取所有的属性- 本类中所有的
        Field[] declaredFields = clazz.getDeclaredFields();
        //遍历
        for (Field f : declaredFields) {
            //获取权限修饰符
            int modifiers = f.getModifiers();
            System.out.print(Modifier.toString(modifiers) + " ");

            //获取类型
            Class type = f.getType();
            System.out.print(type + " ");

            //获取名字
            String name = f.getName();
            System.out.print(name);

            System.out.println();
        }
    }
}

8.哪些情况会导致类的初始化 和 哪些使用类的操作不会导致类的初始化

导致类的初始化

1.主方法所在的类

2.第一次使用就是在new 此时没有初始化

3.调用某个类的静态成员 且没有初始化

4.子类初始化时父类没有初始化,先初始化父类

5.反射操作某个类时 如果类没有初始化也会导致初始化

不会导致初始化

1.某个类的静态常量

2.通过子类调用父类静态变量 方法 只会导致父类初始化

3.用某个类型声明数组并创建对象时, 不会导致这个类的初始化

package com.atguigu.java6;

/*
哪些情况会导致类的初始化
(1)运行主方法所在的类,要先完成类初始化,再执行main方法
(2)第一次使用某个类型就是在new它的对象,此时这个类没有初始化的话,先完成类初始化再做实例初始化
(3)调用某个类的静态成员(类变量和类方法),此时这个类没有初始化的话,先完成类初始化
(4)子类初始化时,发现它的父类还没有初始化的话,那么先初始化父类
(5)通过反射操作某个类时,如果这个类没有初始化,也会导致该类先初始化
        Class.forName("com.atguigu.java6.SupA");


4、哪些使用类的操作不会导致类的初始化?
(1)使用某个类的静态的常量(static  final)
(2)通过子类调用父类的静态变量,静态方法,只会导致父类初始化,不会导致子类初始化,即只有声明静态成员的类才会初始化
(3)用某个类型声明数组并创建数组对象时,不会导致这个类初始化
 */

class SupA{
    static {
        System.out.println("SupA类初始化");
    }

    static int id = 10;

    public static final int AGE = 20;
}
class SubA extends SupA{
    static {
        System.out.println("SubA类初始化");
    }
}
public class ClassInitTest {
    static {
        System.out.println("main方法所在的类");
    }
    public static void main(String[] args) throws ClassNotFoundException {
        System.out.println("aa");

        System.out.println("=================");
//        new SupA();
//        new SupA();

        System.out.println("==============");
        //System.out.println(SupA.id);

        System.out.println("===============");

//        new SubA();

        System.out.println("==================");

        //Class clazz = SupA.class;
       // Class.forName("com.atguigu.java6.SupA");
        //对象名.getClass()

        System.out.println("==================");
        //System.out.println(SupA.AGE);

        System.out.println("====================");
//        System.out.println(SubA.id);

        System.out.println("====================");

        SupA[] s = new SupA[5];
    }
}

9.类加载器

双亲委派 :当类加载时应用程序类加载器先调用父类-扩展类加载器进行调用
        扩展类加载器再调用父类-引导类加载器加载
        引导类加载器只加载核心类库的类,如果该类是核心类库的类则加载否则不加载由儿子加载。
        扩展类加载器只加载jre/lib/ext中的类。如果该类是jre/lib/ext中的类则加载否则由儿子加载。
        应用程序类加载器直接加载。

package com.atguigu.java6;

import org.junit.Test;

/*
    类加载器


    双亲委派 :当类加载时应用程序类加载器先调用父类-扩展类加载器进行调用
        扩展类加载器再调用父类-引导类加载器加载
        引导类加载器只加载核心类库的类,如果该类是核心类库的类则加载否则不加载由儿子加载。
        扩展类加载器只加载jre/lib/ext中的类。如果该类是jre/lib/ext中的类则加载否则由儿子加载。
        应用程序类加载器直接加载。
 */
public class ClassLoaderTest {

    @Test
    public void test() throws ClassNotFoundException {

        //获取类的运行时类的对象(Class对象)
        //自定义的类用的类加载器 - AppClassLoader(应用程序类加载器)
        Class clazz = Class.forName("com.atguigu.java6.A");
        ClassLoader classLoader = clazz.getClassLoader();
        System.out.println(classLoader);


        classLoader = classLoader.getParent();//ExtClassLoader(扩展类加载器)
        System.out.println(classLoader);


        classLoader = classLoader.getParent();
        System.out.println(classLoader);//null -- 引导类加载器(不是Java语言实现的)
    }

    @Test
    public void test2() throws ClassNotFoundException {

        //获取类的运行时类的对象(Class对象)
        //null -- 引导类加载器(不是Java语言实现的)
        Class clazz = Class.forName("java.lang.String");
        ClassLoader classLoader = clazz.getClassLoader();
        System.out.println(classLoader);
    }
}

10.注解与自定义注解

补充说明 不会改变结构

@Override 说明重写

@Deprecated 说明当前结构过时

@SuppressWarnings 抑制警告

package com.atguigu.java7;

/*
    注解:注解用来对类中的一些结构进行补充说明 并不会改变原有的结构

    系统中的注解:
        @Override :用来说明当前方法是一个重写的方法
        @Deprecated : 用来说明当前结构(比如:方法,属性)已经过时
        @SuppressWarnings : 抑制警告(警告不是错误可以忽略)
 */

import java.util.Date;

class A{
    public void show(){}
}
class B extends A{
    @Deprecated
    public int id;

    @Override
    public void show() {
        super.show();
    }

    @Deprecated
    public void say(){

    }
}
public class AnnotationTest {

    public static void main(String[] args) {
        Date date = new Date();
        date.getDate();
        new B().say();

    }

    @SuppressWarnings("all")
    public void say(){
        int id = 10;
    }
}

自定义注解

    格式 :
        权限修饰符 @interface 注解名{

        }

    元注解 :注解上面使用的注解(用来描述注解的注解)
        @Target :用来限制自定义的注解可以用在哪些结构上
        @Retention : 用来描述自定义类的注解的生命周期
                SOURCE :该注解只能用在源码上---字节码文件中就没有该注解了
                CLASS : 在编译阶段到运行阶段 --- 运行以后就没有该注解了(运行时拿不到此注解)
                RUNTIME : 在运行阶段 (如果想要通过反射获取此注解的信息--该注解必须是RUNTIME)
                    注意:只要是自定义注解一定是RUNTIME

package com.atguigu.java7;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/*
    自定义注解

    格式 :
        权限修饰符 @interface 注解名{

        }

    元注解 :注解上面使用的注解(用来描述注解的注解)
        @Target :用来限制自定义的注解可以用在哪些结构上
        @Retention : 用来描述自定义类的注解的生命周期
                SOURCE :该注解只能用在源码上---字节码文件中就没有该注解了
                CLASS : 在编译阶段到运行阶段 --- 运行以后就没有该注解了(运行时拿不到此注解)
                RUNTIME : 在运行阶段 (如果想要通过反射获取此注解的信息--该注解必须是RUNTIME)
                    注意:只要是自定义注解一定是RUNTIME
 */
@Target(value = {ElementType.METHOD,ElementType.FIELD})
@Retention(RetentionPolicy.SOURCE)
@interface MyAnn{
    //属性 = 如果名字叫作value那么在给注解赋值时可以省略不写
    String name() default "longge";//default "longge" : 设置默认值

}

class Emp{
    @MyAnn(name="xiaolongge")//name="xiaolongge" :给注解中的属性赋值
    int id;

//    @Override
//    int age;

    @MyAnn //不用强制给注解中的name赋值了 - 因为name有默认值
    public void show(){

    }
}

public class AnnotationTest2 {
}

11.获得类、属性、方法的注解

package com.atguigu.java8;


import org.junit.Test;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Arrays;

public class AnnotationTest {

    @Test
    public void test() throws NoSuchFieldException, NoSuchMethodException {

        Class clazz = Student.class;

        //拿的是类上的注解
        Annotation[] annotations = clazz.getAnnotations();
        System.out.println(Arrays.toString(annotations));

        System.out.println("====================================");

        //拿属性上的注解
        //获取那个属性
        Field id = clazz.getField("id");
        //获取属性上的注解
        Annotation[] annotations1 = id.getAnnotations();
        System.out.println(Arrays.toString(annotations1));

        System.out.println("====================================");
        //获取方法上的注解
        //获取方法
        Method show = clazz.getMethod("show");
        //获取方法上的注解
        Annotation[] annotations2 = show.getAnnotations();
        System.out.println(Arrays.toString(annotations2));
    }
}

  • 8
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值