Java反射(Class类,Class对象获取)
⽬录
Java反射超详解
1.反射基础
1.1Class类
1.2类加载
2.反射的使⽤
2.1Class对象的获取
2.2Constructor类及其⽤法
2.3Field类及其⽤法
Java反射超详解
1.反射基础
Java反射机制是在程序的运⾏过程中,对于任何⼀个类,都能够知道它的所有属性和⽅法;对于任意⼀个对象,都能够知道它的任意属性和⽅法,这种动态获取信息以及动态调⽤对象⽅法的功能称为Java语⾔的反射机制。
Java反射机制主要提供以下这⼏个功能:
在运⾏时判断任意⼀个对象所属的类
在运⾏时构造任意⼀个类的对象
在运⾏时判断任意⼀个类所有的成员变量和⽅法
在运⾏时调⽤任意⼀个对象的⽅法
1.1Class类
Class类,Class类也是⼀个实实在在的类,存在于JDK的java.lang包中。Class类的实例表⽰java应⽤运⾏时的类(class ans enum)或接⼝(interface and annotation)(每个java类运⾏时都在JVM⾥表现为⼀个c
lass对象,可通过类名.class、类型.getClass()、Class.forName("类名")等⽅法获取class对象)。数组同样也被映射为为class 对象的⼀个类,所有具有相同元素类型和维数的数组都共享该 Class 对象。基本类型boolean,byte,char,short,int,long,float,double和关键字void同样表现为 class 对象。
到这我们也就可以得出以下⼏点信息:
Class类也是类的⼀种,与class关键字是不⼀样的。
⼿动编写的类被编译后会产⽣⼀个Class对象,其表⽰的是创建的类的类型信息,⽽且这个Class对象保存在同名.class的⽂件中(字节码⽂件)。
每个通过关键字class标识的类,在内存中有且只有⼀个与之对应的Class对象来描述其类型信息,⽆论创建多少个实例对象,其依据的都是⽤⼀个Class对象。
Class类只存私有构造函数,因此对应Class对象只能有JVM创建和加载。
Class类的对象作⽤是运⾏时提供或获得某个对象的类型信息,这点对于反射技术很重要(关于反射稍后分析)。
1.2类加载
类加载机制流程:
类的加载:
注:详细的类加载内容,看JVM板块。
2.反射的使⽤
2.1Class对象的获取
在类加载的时候,jvm会创建⼀个class对象。class对象可以说是反射中最常见的。
获取class对象的⽅式的主要三种:
根据类名:类名.class
根据对象:对象.getClass()
根据全限定类名:Class.forName(全限定类名)
public class demo1Main1 {
public static void main(String[] args) throws Exception {
//获取Class对象的三种对象
System.out.println("根据类名:\t" + User.class);
System.out.println("根据对象:\t" + new User().getClass());
System.out.println("根据全限定类名:\t" + Class.forName("demo1.User"));
/
/常⽤的⽅法
Class<User> userClass = User.class;
System.out.println("获取全限定类名:\t" + Name());
System.out.println("获取类名:\t" + SimpleName());
System.out.println("实例化:\t" + wInstance());
}
}
输出结果:
根据类名: class demo1.User
根据对象: class demo1.User
根据全限定类名: class demo1.User
获取全限定类名: demo1.User
获取类名: User
实例化: User{name='init', age=0}
再来看看Class类的⽅法:
toString()
public String toString() {
return (isInterface() ? "interface " : (isPrimitive() ? "" : "class "))
+ getName();
}
toString()⽅法能够将对象转换为字符串,toString()⾸先判断Class类型是否是接⼝类型,也就是说普通类和接⼝都能⽤Class对象表⽰,然后在判断是否是基本数据类型,这⾥判断的都是基本数据类型和包装类,还有void类型。
getName()
获取类的全限定名称。(包括包名)即类的完整名称。
如果是引⽤类型。⽐如 Name()→java.lang.String
如果是基本数据类型。⽐如 Name()→byte
如果是数组类型。⽐如 new Object[3].getClass().getName()→[Ljava.lang.Object;
getSimpleName()
获取类名(不包括包名)。
getCanonicalName()
获取全限定的类名(包括包名)。
toGenericString()
返回类的全限定名称,⽽且包括类的修饰符和类型参数信息。
forName()
根据类名获得⼀个Class对象的引⽤,这个⽅法会使类对象进⾏初始化。
例如:Class t = Class.forName("java.lang.Thread")就能够初始化⼀个Thread线程对象。
在Java中,⼀共有三种获取类实例的⽅式:
Class.forName(java.lang.Thread)
Thread.class
newInstance()
创建⼀个类的实例,代表着这个类的对象。上⾯forName()⽅法对类进⾏初始化,newInstance⽅法对类进⾏实例化。使⽤该⽅法创建的类,必须带有⽆参的构造器。
getClassLoader()
获取类加载器对象。
getInterfaces()
获取当前类实现的类或是接⼝,可能是多个,所以返回的是Class数组。
isInterface()
判断Class对象是否是表⽰⼀个接⼝。
getFields()
获得某个类的所有的公共(public)的字段,包括继承⾃⽗类的所有公共字段。类似的还有getMethods和getConstructors。
getDeclaredFields
获得某个类的⾃⼰声明的字段,即包括public、private和proteced,默认但是不包括⽗类声明的任何字段。类似的还
有getDeclaredMethods和getDeclaredConstructors。
getName、getCanonicalName与getSimpleName的区别:
getSimpleName:只获取类名.
getName:类的全限定名,jvm中Class的表⽰,可以⽤于动态加载Class对象,例如Class.forName。
getCanonicalName:返回更容易理解的表⽰,主要⽤于输出(toString)或log打印,⼤多数情况下和getName⼀样,但是在内部类、数组等类型的表⽰形式就不同了。
列⼦:
;
public class Test {
private class inner{
}
public static void main(String[] args) throws ClassNotFoundException {
//普通类
System.out.println(SimpleName()); //Test
System.out.println(Name()); //Test
System.out.println(CanonicalName()); //Test
//内部类
System.out.println(SimpleName()); //inner
System.out.println(Name()); //Test$inner
System.out.println(CanonicalName()); //Test.inner
//数组
System.out.Class().getSimpleName()); //String[]
System.out.Class().getName()); //[Ljava.lang.String;
System.out.Class().getCanonicalName()); //java.lang.String[]
//我们不能⽤getCanonicalName去加载类对象,必须⽤getName
/
/Class.forName(CanonicalName()); 报错
Class.forName(Name());
}
}
2.2Constructor类及其⽤法
Constructor类存在于反射包(flect)中,反映的是Class 对象所表⽰的类的构造⽅法。
获取Constructor对象是通过Class类中的⽅法获取的,Class类与Constructor相关的主要⽅法如下:
⽅法返回值⽅法名称⽅法说明
Constructor getConstructor(Class<?>… parameterTypes)返回指定参数类型、具有public访问权限的构造函数对象Constructor<?>返回所有具有public访问权限的构造函数的Constructor对象数
[]getConstructors()组
Constructor getDeclaredConstructor(Class<?>…
parameterTypes)返回指定参数类型、所有声明的(包括private)构造函数对象
Constructor<?>
[]
getDeclaredConstructors()返回所有声明的(包括private)构造函数对象
T newInstance()调⽤⽆参构造器创建此 Class 对象所表⽰的类的⼀个新实例。
⽅法返回值⽅法名称⽅法说明
列⼦:
public class ConstructionTest implements Serializable {
public static void main(String[] args) throws Exception {
Class<?> clazz = null;
//获取Class对象的引⽤
clazz = Class.forName("ample.javabase.User");
//第⼀种⽅法,实例化默认构造⽅法,User必须⽆参构造函数,否则将抛异常
User user = (User) wInstance();
user.setAge(20);
user.setName("Jack");
System.out.println(user);
System.out.println("--------------------------------------------");
//获取带String参数的public构造函数
Constructor cs1 =Constructor(String.class);
//创建User
User user1= (User) wInstance("hiway");
user1.setAge(22);
System.out.println("user1:"+String());
System.out.println("--------------------------------------------");
//取得指定带int和String参数构造函数,该⽅法是私有构造private
Constructor DeclaredConstructor(int.class,String.class);
//由于是private必须设置可访问
cs2.setAccessible(true);
//创建user对象
User user2= (User) wInstance(25,"hiway2");
System.out.println("user2:"+String());
System.out.println("--------------------------------------------");
/
/获取所有构造包含private
Constructor<?> cons[] = DeclaredConstructors();
// 查看每个构造⽅法需要的参数
for (int i = 0; i < cons.length; i++) {
//获取构造函数参数类型
Class<?> clazzs[] = cons[i].getParameterTypes();
System.out.println("构造函数["+i+"]:"+cons[i].toString() );
System.out.print("参数类型["+i+"]:(");
for (int j = 0; j < clazzs.length; j++) {
if (j == clazzs.length - 1)
System.out.print(clazzs[j].getName());
else
System.out.print(clazzs[j].getName() + ",");
}
System.out.println(")");
}
}
}
class User {
private int age;
private String name;
public User() {
super();
}
public User(String name) {
super();
this.name = name;
}
/**
* 私有构造
* @param age
* @param name
*/
private User(int age, String name) {
super();
this.age = age;
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "User{" +
"age=" + age +
", name='" + name + '\'' +
'}';
}
}
输出结果:
User{age=20, name='Jack'}
--------------------------------------------
user1:User{age=22, name='hiway'}
--------------------------------------------
user2:User{age=25, name='hiway2'}
java反射获取父类属性--------------------------------------------
构造函数[0]:ample.javabase.User(int,java.lang.String)
参数类型[0]:(int,java.lang.String)
构造函数[1]:ample.javabase.User(java.lang.String)
参数类型[1]:(java.lang.String)
构造函数[2]:ample.javabase.User()
参数类型[2]:()
关于Constructor类本⾝⼀些常⽤⽅法如下(仅部分,其他可查API):
⽅法返
回值
⽅法名称⽅法说明
Class getDeclaringClass() 返回 Class 对象(不包含参数)
Type[] getGenericParameterTypes() 按照声明顺序返回⼀组Type 对象,返回Constructor 对象构造函数的形参类型。
String getName() 以字符串形式返回此构造⽅法的名称。
Class<? >[] getParameterTypes()
按照声明顺
序返回⼀组
Class 对
象,即返回
Constructor
对象所表⽰
构造⽅法形
参类型
使⽤此
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论