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

个人JAVA学习笔记总结(2)(2)

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

个人JAVA学习笔记总结(2)(2)

目录

#java反射机制(简版)

介绍

 ##获取类对象

##使用反射机制进行对象的实例化

##使用有参构造器实例化对象

##使用反射机制调用方法

  后续  

补充注解

反射机制中查看注解

方法上查看注解

在反射机制中获取注解的参数


#java反射机制(简版)

介绍
### java反射机制

反射是java中的动态机制,它允许我们在程序运行期间再确定类的实例化,方法的调用,属性的调用等,而不是传统意义上的在编码期间确定。

因此,反射可以大大的提高代码的灵活度,但是随之而来的是更多的系统开销和较慢的运行速度,因此不能过度的依赖反射。
#### Class类

Class的每一个实例用于表示JVM加载的一个类,所以我们也称Class的实例
为类的类对象。
当JVM加载一个类时会同时实例化一个Class的实例与之对应,这个Class实例
中会保存该类的一切信息(类名,有哪些方法,构造器,属性,注解等等)
我们在程序运行期间通过某个类的类对象来操作这个类。因此使用反射操作某个
类的第一件事就是获取该类的类对象

 ##获取类对象
#### 获取一个类的类对象有三种方式:

- 1:类名.class
  例如:
  Class cls = String.class;
  Class cls = int.class (基本类型只能通过这种方式获取类对象)

- 2:Class.forName(String className)
  通过Class的静态方法forName,传入对应类的完全限定名(包名.类名)的
  形式获取类对象
  Class cls = Class.forName("java.lang.String");

- 3:通过类加载器ClassLoader加载类对象
import java.lang.reflect.Method;


public class ReflectDemo1 {
    public static void main(String[] args) throws ClassNotFoundException {
        


        
        
        //获取String的类对象
//        Class cls = String.class;

        
//        Class cls = Class.forName("java.lang.String");



        
        
        ClassLoader classLoader = ReflectDemo1.class.getClassLoader();
        Class cls = classLoader.loadClass("java.lang.String");

        //查看类名
        //获取类的完全限定名(包名.类名)
        String className = cls.getName();
        System.out.println("类名:"+className);
        //仅获取类名
        className = cls.getSimpleName();
        System.out.println("类名:"+className);

        //通过类对象获取其表示的类的所有方法
        //获取所有公开方法和从超类继承的方法
//        Method[] methods = cls.getMethods();
//        for(Method method : methods){
//            System.out.println(method.getName());
//        }

        //获取本类定义的方法(包含私有方法,但是不含有从超类继承的方法)
        Method[] methods = cls.getDeclaredMethods();
        for(Method method : methods){
            System.out.println(method.getName());
        }
    }
}

##使用反射机制进行对象的实例化
##### Class提供的方法:

Object newInstance()

该方法可以使用其表示的类的无参构造器进行对象实例化
public class ReflectDemo2 {
//    public static void main(String[] args) throws ClassNotFoundException, //IllegalAccessException, InstantiationException { //可以每个抛出异常
    public static void main(String[] args) throws Exception { //可以抛出一个大异常
        Person p = new Person();//硬编码,编码期间确定实例化那个类
        System.out.println(p);

        
        //1加载类对象
//        Class cls = Class.forName("reflect.Person");

//        Scanner scanner = new Scanner(System.in);
//        System.out.println("请输入要实例化的类名 : ");
//        String className = scanner.nextLine();
//        Class cls = Class.forName(className);
        ClassLoader classLoader = ReflectDemo02.class.getClassLoader(); //获取加载类
        Class cls = classLoader.loadClass("reflect.Person"); //开始加载输入的类

        //2.类对象直接提供了可以通过公开的无参构造器实例化的功能
        Object o = cls.newInstance();//调用无参构造器
        System.out.println(o);

    }
}

##使用有参构造器实例化对象
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;


public class ReflectDemo3 {
    public static void main(String[] args) throws Exception {
        Person p = new Person("苍老师",55);//传参.会覆盖原有参数,不写参数,则会输出原有参数
        System.out.println(p);

        //加载类对象
        Class cls = Class.forName("reflect.Person");

        //获取Person的构造器Person(String ,int)
//        cls.getConstructor();//不传任何参数时获取的仍然是无参构造器
        //获取无参构造器
//        Constructor c = cls.getConstructor();
//        Object o  = c.newInstance();

        //先获取指定的构造器:Person(String name,int age)
        Constructor c = cls.getConstructor(String.class,int.class);
        Object o  = c.newInstance("苍老师",55);//实例化时要传入构造器要求的实际参数
        System.out.println(o);
    }
}

##使用反射机制调用方法

        ### 调用无参数方法(比较省事代码少,但是有点"死")

import java.lang.reflect.Method;
import java.util.Scanner;


public class ReflectDemo04 {
    public static void main(String[] args) throws Exception{
        Person p = new Person();
        p.sayHello();
//        Scanner scanner = new Scanner(System.in);
//        System.out.println("请输入类名 : ");
//        String className = scanner.nextLine();
//        System.out.println("请输入方法名 : ");
//        String methodName = scanner.nextLine();

        //1.实例化
        Class cls = Class.forName("reflect.Person");
//        Class cls = Class.forName(className);

        Object obj = new Person();
//        Object obj = cls.newInstance();

        //2调用方法
        //2.1通过类对象获取要调用的方法
        Method method = cls.getMethod("sayHello");//获取的是无参的sayHello方法
//        Method method = cls.getMethod(methodName);//获取的是无参的sayHello方法
        //2.2通过获取的方法对象来调用该方法
//        obj.sayHello();  //因为obj指向的是及一个Person对象,因此反射机制可以调用到它的sayHello()
        method.invoke(obj);
    }
}

                方法二(比较麻烦,但是灵活)

import java.lang.reflect.Method;
import java.util.Scanner;


public class ReflectDemo04 {
    public static void main(String[] args) throws Exception{
        Person p = new Person();
        p.sayHello();
        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入类名:");
        String className = scanner.nextLine();
        System.out.println("请输入方法名:");
        String methodName = scanner.nextLine();

        //实例化
        ClassLoader classLoader = ReflectDemo04.class.getClassLoader();
//        Class cls = classLoader.loadClass("reflect.Person");
        Class cls = classLoader.loadClass(className);
        Object o = cls.newInstance();// == new Person()

        //调用方法
        //1通过类对象获取要调用的方法
//        Method method = cls.getMethod("sayHello");//获取无参方法sayHello
        Method method = cls.getMethod(methodName);
        //2通过方法对象执行该方法
        method.invoke(o);//o.sayHello()   o实际上是一个Person对象
    }
}

        ###调用有参方法

import java.lang.reflect.Method;


public class ReflectDemo5 {
    public static void main(String[] args) throws Exception {
        Class cls = Class.forName("reflect.Person");
        Object obj = cls.newInstance();
        //doSomeThing(String)
        Method method = cls.getMethod("doSomeThing", String.class); //第一个传入有参方法名,            
                                                                 //第二传入所属类型的 .class
        method.invoke(obj,"玩游戏");
        //p.doSomeThing("玩游戏");

        //doSomeThing(String,int)
        Method method1 = cls.getMethod("doSomeThing", String.class,int.class); //同上
        method1.invoke(obj,"作业",5);  //方法名,String类型参数,int型参数
        //p.doSomeThing("作业",5);

    }
}

        ###访问私有方法

import java.lang.reflect.Method;


public class ReflectDemo6 {
    public static void main(String[] args) throws Exception {
        Person p = new Person();
//        p.hehe();//编译不通过!

        Class cls = Class.forName("reflect.Person");
        Object o = cls.newInstance();

        
//        Method[] methods = cls.getMethods(); //获取所有公开方法,不包含私有
//        Method[] methods = cls.getDeclaredMethods(); //获取所有公开方法,包含私有
//        for(Method method : methods){ 
//            System.out.println(method.getName());
//        }

        //调用自己的方法,不含有继承的
        Method method = cls.getDeclaredMethod("dosome");
        method.setAccessible(true);//强行打开dosome方法的访问权限
        method.invoke(obj);//p.dosome()
    }
}

  后续  
 
 
import java.io.File;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.net.URISyntaxException;


public class ReflectDemo7 {
    
    public static void main(String[] args) throws Exception {
        
        //1这里的当前目录表示的是当前ReflectDemo7这个类所在最外层包的上一级目录
//        File dir = new File(
//                ReflectDemo7.class.getClassLoader().getResource(".").toURI()
//        );

        //2这里的当前目录就是当前类所在的目录
        File dir = new File(
                ReflectDemo7.class.getResource(".").toURI()
        );

        System.out.println(dir.getName());

        //通过当前类ReflectDemo7的类对象获取所在的包名
        String packageName = ReflectDemo7.class.getPackage().getName();
        System.out.println("ReflectDemo7类的包名是:"+packageName);

        //获取ReflectDemo7.class文件所在的目录中所有.class文件
        File[] subs = dir.listFiles(f->f.getName().endsWith(".class"));
        for(File sub : subs){
            //获取字节码文件的文件名
            String fileName = sub.getName();
            System.out.println(fileName);
            
            String className = fileName.substring(0,fileName.indexOf("."));
//            System.out.println("类名:"+className);

            //加载该类的类对象
            Class cls = Class.forName(packageName+"."+className);
            Object obj = cls.newInstance();
//            System.out.println("加载的类为:"+cls.getName());
            //通过类对象获取本类定义的所有方法
            Method[] methods = cls.getDeclaredMethods();
            //遍历每个方法,检查哪个方法是无参的
            for(Method method : methods){
                if(
                        method.getParameterCount()==0
                        &&
                        method.getModifiers() == Modifier.PUBLIC
                ){
                    System.out.println("自动调用"+className+"的方法:"+method.getName());
                    method.invoke(obj);
                }
            }

        }


    }
}

补充注解

补充注解部分转自

版权声明:本文为CSDN博主「程序媛 泡泡」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_43884234/article/details/115055781

        注解的分类
注解一共分为3大类,我们先来认识一下:JDK自带注解
元注解
自定义注解
 

2.1 JDK注解
JDK注解的注解,就5个:

@Override :用来标识重写方法
@Deprecated标记就表明这个方法已经过时了,但我就要用,别提示我过期
@SuppressWarnings(“deprecation”) 忽略警告
@SafeVarargs jdk1.7出现,堆污染,不常用
@FunctionallInterface jdk1.8出现,配合函数式编程拉姆达表达式,不常用

2.2 元注解
用来描述注解的注解,就5个:

@Target 注解用在哪里:类上、方法上、属性上等等
@Retention 注解的生命周期:源文件中、字节码文件中、运行中
@Inherited 允许子注解继承
@Documented 生成javadoc时会包含注解,不常用
@Repeatable注解为可重复类型注解,可以在同一个地方多次使用,不常用

2.2.1 @Target ElementType…
描述注解存在的位置:

ElementType.TYPE 应用于类的元素
ElementType.METHOD 应用于方法级
ElementType.FIELD 应用于字段或属性(成员变量)
ElementType.ANNOTATION_TYPE 应用于注解类型
ElementType.CONSTRUCTOR 应用于构造函数
ElementType.LOCAL_VARIABLE 应用于局部变量
ElementType.PACKAGE 应用于包声明
ElementType.PARAMETER 应用于方法的参数
2.2.2 @Retention RetentionPolicy…
该注解定义了自定义注解被保留的时间长短,比如某些注解仅出现在源代码中,而被编译器丢弃;而另一些却被编译在class文件中; 编译在class文件中的注解可能会被虚拟机忽略,而另一些在class被装载时将被读取。
为何要分字节码文件中有还是没有呢?如果没有时,反射技术就拿不到,从而就无法去识别处理。它的值一共3种:

SOURCE 在源文件中有效(即源文件保留)
CLASS 在class文件中有效(即class保留)
RUNTIME 在运行时有效(即运行时保留)

3 自定义注解
注意:注解的语法写法和常规java的语法写法不同
创建包: cn.tedu. annotation
创建类: TestAnnotation.java

package cn.tedu.annotation;

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


public class TestAnnotation {
}
//2.通过@Target注解标记自定义注解的使用位置

@Target({ElementType.METHOD,ElementType.TYPE})//可以加在方法&类上
//3.通过@Retention注解标记自定义注解的生命周期

@Retention(RetentionPolicy.RUNTIME)//到运行时都有效
//1.定义自定义注解

@interface Rice{
    //5.我们可以给注解进行功能增强--添加注解的属性
   
    //int age();//给自定义注解添加一个普通属性age,类型是int
    int age() default 0;//给自定义注解的普通属性赋予默认值0
   
    //String value();//定义一个特殊属性value,类型是String
    String value() default "Lemon";//定义特殊属性并给特殊属性赋予默认值
}

//4.定义一个类用来测试自定义注解
//@Rice
class TestAnno{
   
    //@Rice//报错了
    String name;
   
   
   
    @Rice(age=10,value="orange")
    //@Rice("Apple")
    //@Rice(age = 10)
    //@Rice(10)//报错,不可以简写,普通属性没有这种格式
    public void eat(){
        System.out.println("干饭不积极,思想有问题");
    }
}

反射机制中查看注解
 
public class ReflectDemo8 {
    public static void main(String[] args) throws Exception {
//        Class cls = Class.forName("reflect.Person");
        Class cls = Class.forName("reflect.ReflectDemo7");

        //判断当前类对象所表示的类是否被注解@AutoRunClass标注了?
        boolean tf = cls.isAnnotationPresent(AutoRunClass.class);
        if(tf){
            System.out.println(cls.getName()+":被注解@AutoRunClass标注了!");
        }else{
            System.out.println(cls.getName()+":没有被注解@AutoRunClass标注了!");
        }

    }
}

方法上查看注解
 
public class ReflectDemo9 {
    public static void main(String[] args) throws Exception {
        Class cls = Class.forName("reflect.Person");
        Method[] methods = cls.getDeclaredMethods();
        for(Method method : methods){
            
            if(method.isAnnotationPresent(AutoRunMethod.class)){
                System.out.println(method.getName()+":被注解@AutoRunMethod标注了");
            }else{
                System.out.println(method.getName()+":没有被注解@AutoRunMethod标注了");
            }
        }


    }
}

在反射机制中获取注解的参数
 
public class ReflectDemo10 {
    public static void main(String[] args) throws Exception {
        Class cls = Class.forName("reflect.Person");
        Method[] methods = cls.getDeclaredMethods();
        for(Method method : methods){
            //判断该方法是否被注解@AutoRunMethod标注了
            if(method.isAnnotationPresent(AutoRunMethod.class)){
                //通过方法对象获取该注解
                AutoRunMethod arm = method.getAnnotation(AutoRunMethod.class);
                int value = arm.value();
                System.out.println(
                        "方法"+method.getName()+
                        "上的注解AutoRunMethod指定的参数值为:"+value
                );
            }
        }
    }
}

 

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

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

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