注解与反射

内置注解:

@Override:表示一个方法打算重写

@Deprecated:表示不鼓励程序员使用这样的元素

@SuppressWarnings:用来抑制编译时的警告信息

元注解:

Target 表示我们的注解可以用在那些地方

Retention 表示我们的注解在什么地方还有效(runtime>class>sources)

Documented 表示是否将我们的注解生成在JAVAdoc中

Inherited 子类可以继承父类的注解

自定义注解:

使用@interface自定义注解时,自动继承了java.lang.annotation.Annotation接口

格式:public @interface 注解名 {定义内容}

public class test{
    //注解可以显示赋值,如果没有默认值的default,我们就必须给注解赋值
    @MyAnnotation(age  = 18)
    public void test(){}
    
}
@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation{
    //注解的参数: 参数类型 + 参数名();
    String name() default "";
    int age();
    int id() default -1;//如果默认值为-1,代表不存在
    String[] schools() default{"重庆城市科技学院"}
}

注意:当参数只有一个时,参数名用value

反射:

获取Class类的实例

1)若已知具体的类,通过类的class属性获取,该方法最为安全可靠,程序性能最高

Class clazz  = Person.class

2)已知某个类的实例,调用该实例的getClass()方法获取Class对象

Class clazz  = person.getClass

3)已知一个类的全类名,且该类在类路径下,可通过Class类的静态方法forName()获取,可能抛出ClassNotFoundException

Class clazz = Class.forName("com.mysql.jdbc.Driver")

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

5)可以利用ClassLoader

注意:也可以获得父类类型

Clazz clazz1 = clazz.getSuperclass();

那些类型可以有Class对象

class:外部类,成员(成员内部类,静态内部类),局部内部类,匿名内部类

interface:接口

[]:数组

enum:枚举

annotation:注解@interface

primittive type:基本数据类型

void

Class clazz = Object.class;//类
Class clazz = Comparable.class;//接口
Class clazz = String[].class;//数组
Class clazz = int[][].class;//二维数组
Class clazz = override.class;//注解
Class clazz = ElementType.class;//枚举
Class clazz = Interger.class; //基本数据类型
Class clazz = Class.class;//Class
Class clazz = void.class;//void

注意:只要是元素类型与维度一样,就是同一个Class.

int[] a = new int[10];
int[] b = new int[100];
System.out.println(a.getClass().hashCode());//与下列值一致
System.out.println(b.getClass().hashCode());

什么时候会发生类的初始化

​ 类的主动引用(一定会发生类的初始化)

​ 当虚拟机启动,先初始化main方法所在的类

​ new 一个类的对象

​ 调用类的静态成员(除了final常量)和静态方法

​ 使用Java.lang.reflect包的方法对类进行反射调用

​ 当初始化一个类,如果其父类没有被初始化,则先会初始化他的父类

​ 类的被动引用(不会发生类的初始化)

​ 当访问一个静态域时,只有真正申明这个域的类才会被初始化。如:当通过子类引用父类的静态变量,不会导致子类初始化

​ 通过数组定义类的引用,不会触发此类的初始化

​ 引用常量不会触发此类的初始化(常量在链接阶段就存入调用类的常量池中了)

类加载器

作用:是用来把(class)装载进内存的

类型:引导类加载器:负责Java平台核心库 lib/rt.jat。该加载器无法直接获取

​ 扩展类加载器:负责jre/lib/ext目录下的jar包或-D Java.ext.dirs指定目录下的jar包装入工作室

​ 系统类加载器:Java -classpath 或 -D java.class.path所指的目录下的类与jar包装入工作,是最常见的加载器

//获取系统类加载器
ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
System.out.println(systemClassLoader);//sun.misc.Launcher$AppClassLoader@73d16e93

//获取系统类加载器的父类加载器-->扩展类加载器
ClassLoader parent  = systemClassLoader.getParent();
System.out.println(parent);//sun.misc.Launcher$ExtClassLoader@15db9742

//获取扩展类加载器的父类加载器-->根加载器
ClassLoader parent1 = parent.getParent();
System.out.println(parent1);//null

//测试当前类是哪个加载器加载的
ClassLoader classLoader = Class.forName("com.mysql.jdbc.Driver").getClassLoader();
System.out.println(classLoader);//sun.misc.Launcher$AppClassLoader@73d16e93

//测试JDK内置的类是谁加载的
ClassLoader classLoader = Class.forName("java.lang.Object").getClassLoader();
System.out.println(classLoader);//null

//如何获取系统类加载器可以加载的路径
System.out.println("java.class.path")
    
//双亲委派机制
    如果定义了和JDK中相同路径的包 那一定是运行JDK中的

获得类中的信息

//一般通过Class类的静态方法forName()获取Class对象(当然也可以用其他两种)
Class.forName("com.reflection.User")
//获得类的名字
System.out.println(c1.getName());//获得包名+类名
System.out.println(c1.getSimpleName());//类名

//获取类的属性
File[] fields = c1.getFileds();//只能找到public属性的
File[] fields = c1.getDeclaredFileds();//找到全部的属性

//获得指定属性的值
File[] fields = c1.getFiled("name");//要确保name为public才能获得
File[] fields = c1.getDeclaredFiled("name");
/*
获得类的方法
getMethods();  //获得本类及其父类的全部public方法
getDeclaredMethods();//获得本类的所有方法(不包括其父类)

//获取指定的方法
Method getName = c1.getMethod( name: "getName",...parameterTypes: null);
Method setName = cl.getMethod( name: "setName",..parameterTypes: string.class);
system.out.println(getName) ;
system.out. println(setName) ;


//获得构造器
getConstructors();//pubic
getDeclaredConstructors();//全部


/获得指定的构造器
Constructor declaredConstructor = c1.getDeclaredConstructor(String.class,int.class,int.class);
system.out.println("指定: "+declaredconstructor ) ;


*/



创建类的对象:调用class对象的newInstance()方法

1)类必须有一个无参数的构造器

2)类的构造器的访问权限需要足够

注意:并不是没有无参的构造器就不能创建对象,只要在操作的时候明确的调用类中的构造器,并将参数传递进去之后,就可以实例化操作

//获取class对象
Class c1 = Class.forName("com.reflection.User");

//创造一个对象
User user = (User)c1.newInstance();//本质上是调用了类的无参构造
System.out.println(user)

//通过构造器创建对象
Constructor constructor = c1.getDeclaredConstructor(String.classint.classint.class);
User user2 = (User)constructor.newInstance( ...initargs:"秦疆"00118);
System.out.println(user2);

//通过反射调用普通方法
User user3 = (User)c1.newInstance();
//通过反射获取一个方法
Method setName = c1.getDeclaredMethod( name: "setName",string.class);
//invoke :激活的意思
//(对象,"方法的值")
setName.invoke(user3,"狂神")
system.out.println(user3.getName());


		
//通过反射操作属性
User user4 = (User)c1.newInstance();
Field name = c1.getDeclaredField( name: "name" );
//不能直接操作私有属性,我们需要设置可访问权限为true
name.setAccessible(true); //setAccessible-设置可访问的(设置访问性) true可访问 false不可访问
name.set(user4, "狂神2");
system.out.println(user4.getName());


性能对比

普通方法>反射方式(设置可访问权限)>一般反射方式

获取泛型信息https://www.bilibili.com/video/BV1p4411P7V3?p=15&spm_id_from=pageDriver

获取注解信息https://www.bilibili.com/video/BV1p4411P7V3?p=16&spm_id_from=pageDriver

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值