注解与反射
注解
注解:就是以@开头的
比如:@Override
内置注解
例如:
@Override:重写注解
@Deprecated:表示已过时的注解(不推荐使用某方法)
@SuppressWarnings(String[] value()):镇压警告,参数是value=一个字符串数组
元注解
修饰其他注解的注解
@Target:描述注解的使用范围
@Retention:表示在什么级别保留注解信息,用于描述注解的生命周期
(SOURCE<CLASS<RUNTIME)
......
自定义注解
//元注解修饰自定义注解
@Target(value= {ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
//自定义注解,写法:public @interface 注解名
public @interface MyAnotation{
String name() default "qs";//注解参数,这里默认值为qs,写法:类型 名()
int[] num();//注解参数
}
//由public修饰的类时,自定义注解不用写public
反射
反射机制:Java有一个很特别的类——Class,java的所有类都有一个Class对象,该对象记录关于对应的类的信息,所有类都只有一个Class对象,Class对象是由JVM(Java虚拟机)创建的,自己不能实例化class对象
通过引入java.lang.reflect.* 我们可以获取对应的类对象的构造器、方法、属性等,还可以实例化类对象对应的类从而获得一个对象
获取类对象的方式
-
对象.getClass()
import java.lang.reflect.*; public class test { public static void main(String[] args){ User user = new User(); Class c = user.getClass(); System.out.println(c); } } class User{ public String name="qq"; public User(String n){ this.name = n; } public User(){ } }
-
Class.ForName()
import java.lang.reflect.*; public class test { public static void main(String[] args) throws ClassNotFoundException{ Class c = Class.ForName("testReflaction/User"); System.out.println(c); } } class User{ public String name="qq"; public User(String n){ this.name = n; } public User(){ } }
-
类名.class
import java.lang.reflect.*; public class test { public static void main(String[] args){ Class c = User.class; System.out.println(c); } } class User{ public String name="qq"; public User(String n){ this.name = n; } public User(){ } }
所有类型的class对象
- 类有class对象:object.class
- 数组有class对象:String[].class
- 接口有class对象:Comparable.class
- 二维数组有class对象
- 注解有class对象:Override.class
- 枚举有class对象:ElementType.class
- 基本数据类型有class对象
- void有class对象:void.class
- Class类本身有class对象:class.class
类加载内存和类初始化
类的加载:把class文件的字节码读入内存,把静态数据转换为方法区运行时数据结构,并生成一个Class对象表示该类
链接:
- 验证:确保类信息符合JVM规范
- 准备:正式为静态变量(类变量)分配内存并设置默认值,这些内存在方法区分匹配
- 解析:把虚拟机常量池内的符号引用(常量名引用)转换为直接引用(地址引用)
初始化:执行类构造器
class Test{
static{
...
}
static int a = 100;
public Test(){
...
}
}
//如以上代码,把这里的static修饰的变量和static代码块里面的代码合并起来就是类构造器方法
//而Test()这个方法才是构造方法
初始化一个类,发现其父类没有初始化,会首先初始化父类
虚拟机会保证一个类的构造器方法在多线程环境被正确加锁和同步
什么时候类会初始化:
主动引用:
- new的时候
- 反射的时候
类加载器
类缓存:类被加载到加载器,会维持加载一段时间,JVM垃圾回收机制可以回收这些缓存的类的class对象
类加载器类型:
-
引导类加载器(根加载器,c++写的无法获取)
-
扩展类加载器
-
系统类加载器(常用)
package testReflaction;
public class ClassLoader {
public static void main(String[] args){
java.lang.ClassLoader loader1 = java.lang.ClassLoader.getSystemClassLoader();
System.out.println(loader1);//打印系统类加载器
java.lang.ClassLoader loader2 = loader1.getParent();
System.out.println(loader2);//打印扩展类加载器
java.lang.ClassLoader loader3 = loader2.getParent();
System.out.println(loader3);//打印根类加载器,无法获取显示为空
}
}
获取类运行时结构
获取类名:
类对象.getName()——获取包名+类名
类对象.getSimpleName()——获取类名
获取类属性
类对象.getFields()——只获取public属性
类对象.getDeclaredFields()——获取所有属性
类对象.getField("属性名")——获得指定public属性
类对象.getDeclaredFields("属性名")——获取指定的非public属性
package testReflaction;
import java.lang.reflect.*;
public class test {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException,NoSuchMethodException{
Class c1 = Class.forName("testReflaction.User");//获取类对象
//获取类名
System.out.println("获取类名:");
System.out.println(c1.getName());//获取并打印包名+类名
System.out.println(c1.getSimpleName());//获取并打印类名
//获取类属性
System.out.println("获取类属性:");
System.out.println("___________________________________________");
Field[] fields = c1.getFields();
for(Field field:fields){
System.out.println(field);
}
System.out.println("");
for (Field f : c1.getDeclaredFields()){
System.out.println(f);
}
Field f1 = c1.getField("name");
Field f2 = c1.getDeclaredField("a");
System.out.println("获取指定属性:\n" + f1 + "\n" + f2);
}
}
class User{
public String name="qq";
static int a = 1;
int b = 3;
public User(String n){
this.name = n;
}
public User(){
}
public String getName(){
return this.name;
}
public int getA(){
return a;
}
int getB(){
return b;
}
}
获取类方法
类对象.getMethod()——获取指定public方法
类对象.getMethods()——获取所有public方法
类对象.getDeclaredMethod()——获取指定非Public方法
类对象.getDeclaredMethods()——获取所有非public方法
package testReflaction;
import java.lang.reflect.*;
public class test {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException,NoSuchMethodException{
Class c1 = Class.forName("testReflaction.User");//获取类对象
//获取类方法
System.out.println("获取类方法:");
Method[] methods = c1.getMethods();
System.out.println("getMethods:");
for (Method m : methods){
System.out.println(m);
}
System.out.println("getDeclaredMethods:");
for (Method m1 : c1.getDeclaredMethods()){
System.out.println(m1);
}
Method m3 = c1.getDeclaredMethod("getB");
System.out.println(m3);
Method m4 = c1.getMethod("getA");
System.out.println(m4);
}
}
class User{
public String name="qq";
static int a = 1;
int b = 3;
public User(String n){
this.name = n;
}
public User(){
}
public String getName(){
return this.name;
}
public int getA(){
return a;
}
int getB(){
return b;
}
}
获取构造方法
类对象.getConstructor():获取指定的公有构造方法
类对象.getConstructors():获取类中所有公有构造方法
类对象.getDeclaredConstructor():获取指定的构造方法
类对象.getDeclareConstructors():获取类的所有构造方法
package testReflaction;
import java.lang.reflect.*;
public class test {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException,NoSuchMethodException{
Class c1 = Class.forName("testReflaction.User");//获取类对象
//获取构造方法
System.out.println("___________________________________________");
System.out.println("获取构造方法:");
for (Constructor c : c1.getConstructors()){
System.out.println(c);
}
for (Constructor c2 : c1.getDeclaredConstructors()){
System.out.println(c2);
}
System.out.println(c1.getConstructor(String.class));
System.out.println(c1.getDeclaredConstructor());
}
}
class User{
public String name="qq";
static int a = 1;
int b = 3;
public User(String n){
this.name = n;
}
public User(){
}
public String getName(){
return this.name;
}
public int getA(){
return a;
}
int getB(){
return b;
}
}
通过反射动态创建对象
package testReflaction;
import java.lang.reflect.*;
public class test {
public static void main(String[] args) throws ClassNotFoundException, InvocationTargetException,IllegalAccessException,InstantiationException{
Class c1 = Class.forName("testReflaction.User");//获取类对象
//创建对象
//newInstance()
User user = (User)c1.newInstance();
System.out.println(user);
//通过构造器创建
Constructor c = c1.getDeclaredConstructor(String.class);
User use = (User)c.newInstance("小d");
System.out.println(use);
//调用方法
Method getA = c1.getMethod("getA",null);
getA.invoke(use,null);
}
}
class User{
public String name="qq";
static int a = 1;
int b = 3;
public User(String n){
this.name = n;
}
public User(){
}
public String getName(){
return this.name;
}
public int getA(){
return a;
}
int getB(){
return b;
}
}
反射机制很重要,在java反序列化时会用到,可以用来获取一些自定义类的信息,还可以利用JAVA本身自带的包中的类来执行系统命令或执行代码,在框架中也会用到
接下来会去学习并记录一些JAVA反序列化的实战,以及框架方面的知识