Java基础系列文章
Java基础(一):语言概述
Java基础(二):原码、反码、补码及进制之间的运算
Java基础(三):数据类型与进制
Java基础(四):逻辑运算符和位运算符
Java基础(五):流程控制语句
Java基础(六):数组
Java基础(七):面向对象编程
Java基础(八):封装、继承、多态性
Java基础(九):Object 类的使用
Java基础(十):关键字static、代码块、关键字final
Java基础(十一):抽象类、接口、内部类
Java基础(十二):枚举类
Java基础(十三):注解(Annotation)
Java基础(十四):包装类
Java基础(十五):异常处理
Java基础(十六):String的常用API
Java基础(十七):日期时间API
Java基础(十八):java比较器、系统相关类、数学相关类
Java基础(十九):集合框架
Java基础(二十):泛型
Java基础(二十一):集合源码
Java基础(二十二):File类与IO流
Java基础(二十三):反射机制
动态语言
的关键
运行期间
借助于Reflection API取得任何类的内部信息这个对象就像一面镜子,透过这个镜子看到类的结构,所以,我们形象的称之为:反射
解剖
一个类,必须先要获取到该类的Class对象java.lang.Class
:代表一个类理论上:
public final native Class<?> getClass();
内存结构上:
说明:上图中字符串常量池在JDK6中存储在方法区;JDK7及以后,存储在堆空间
哪些类型可以有Class对象:
简言之,所有Java类型!
(1)class:外部类,成员(成员内部类,静态内部类),局部内部类,匿名内部类
(2)interface:接口
(3)[]:数组
(4)enum:枚举在这里插入代码片
(5)annotation:注解@interface
(6)primitive type:基本数据类型
(7)void
Class c1 = Object.class;
Class c2 = Comparable.class;
Class c3 = String[].class;
Class c4 = int[][].class;
Class c5 = ElementType.class;
Class c6 = Override.class;
Class c7 = int.class;
Class c8 = void.class;
Class c9 = Class.class;
Class clazz1 = User.class;
User u1 = new User();
Class clazz2 = u1.getClass();
String className = "com.xc.User"; //全类名
Class clazz3 = Class.forName(className);
Class clazz4 = ClassLoader.getSystemClassLoader().loadClass("com.xc.User");
示例代码:
public class TestCreateObject {
@Test
public void test1() throws InstantiationException, IllegalAccessException {
// 1、没有空参构造抛出:InstantiationException实例化异常
// 2、权限不够抛出:IllegalAccessException非法访问异常
Class clazz = Person.class;
//创建Person类的实例
Person per = (Person) clazz.newInstance();
System.out.println(per);
}
@Test
public void test2()throws Exception{
//(1)获取Class对象
Class<?> clazz = Class.forName("com.atguigu.ext.demo.AtGuiguDemo");
/*
* 获取AtGuiguDemo类型中的有参构造
* 如果构造器有多个,我们通常是根据形参【类型】列表来获取指定的一个构造器的
* 例如:public AtGuiguDemo(String title, int num)
*/
//(2)获取构造器对象
Constructor<?> constructor = clazz.getDeclaredConstructor(String.class,int.class);
//(3)创建实例对象
// T newInstance(Object... initargs) 这个Object...是在创建对象时,给有参构造的实参列表
Object obj = constructor.newInstance("尚硅谷",2022);
System.out.println(obj);
}
}
//1.实现的全部接口
public Class<?>[] getInterfaces()
//确定此对象所表示的类或接口实现的接口。
//2.所继承的父类
public Class<? Super T> getSuperclass()
//返回表示此 Class 所表示的实体(类、接口、基本类型)的父类的 Class。
//3.全部的构造器
public Constructor<T>[] getConstructors()
//返回此 Class 对象所表示的类的所有public构造方法。
public Constructor<T>[] getDeclaredConstructors()
//返回此 Class 对象表示的类声明的所有构造方法。
//Constructor类中:
//取得修饰符:
public int getModifiers();
//取得方法名称:
public String getName();
//取得参数的类型:
public Class<?>[] getParameterTypes();
//4.全部的方法
public Method[] getDeclaredMethods()
//返回此Class对象所表示的类或接口的全部方法
public Method[] getMethods()
//返回此Class对象所表示的类或接口的public的方法
//Method类中:
public Class<?> getReturnType()
//取得全部的返回值
public Class<?>[] getParameterTypes()
//取得全部的参数
public int getModifiers()
//取得修饰符
public Class<?>[] getExceptionTypes()
//取得异常信息
//5.全部的Field
public Field[] getFields()
//返回此Class对象所表示的类或接口的public的Field。
public Field[] getDeclaredFields()
//返回此Class对象所表示的类或接口的全部Field。
//Field方法中:
public int getModifiers()
//以整数形式返回此Field的修饰符
public Class<?> getType()
//得到Field的属性类型
public String getName()
//返回Field的名称。
//6. Annotation相关
get Annotation(Class<T> annotationClass)
getDeclaredAnnotations()
//7.泛型相关
//获取父类泛型类型:
Type getGenericSuperclass()
//泛型类型:ParameterizedType
//获取实际的泛型类型参数数组:
getActualTypeArguments()
//8.类所在的包
Package getPackage()
public class FieldTest {
@Test
public void test1(){
Class clazz = Person.class;
//getFields():获取到运行时类本身及其所有的父类中声明为public权限的属性
// Field[] fields = clazz.getFields();
//
// for(Field f : fields){
// System.out.println(f);
// }
//getDeclaredFields():获取当前运行时类中声明的所有属性
Field[] declaredFields = clazz.getDeclaredFields();
for(Field f : declaredFields){
System.out.println(f);
}
}
//权限修饰符 变量类型 变量名
@Test
public void test2(){
Class clazz = Person.class;
Field[] declaredFields = clazz.getDeclaredFields();
for(Field f : declaredFields){
//1.权限修饰符
/*
* 0x是十六进制
* PUBLIC = 0x00000001; 1 1
* PRIVATE = 0x00000002; 2 10
* PROTECTED = 0x00000004; 4 100
* STATIC = 0x00000008; 8 1000
* FINAL = 0x00000010; 16 10000
* ...
*
* 设计的理念,就是用二进制的某一位是1,来代表一种修饰符,整个二进制中只有一位是1,其余都是0
*
* mod = 17 0x00000011
* if ((mod & PUBLIC) != 0) 说明修饰符中有public
* if ((mod & FINAL) != 0) 说明修饰符中有final
*/
int modifier = f.getModifiers();
System.out.print(Modifier.toString(modifier) + "\t");
// //2.数据类型
Class type = f.getType();
System.out.print(type.getName() + "\t");
//
// //3.变量名
String fName = f.getName();
System.out.print(fName);
//
System.out.println();
}
}
}
public class MethodTest {
@Test
public void test1() {
Class clazz = Person.class;
// getMethods():获取到运行时类本身及其所有的父类中声明为public权限的方法
// Method[] methods = clazz.getMethods();
//
// for(Method m : methods){
// System.out.println(m);
// }
// getDeclaredMethods():获取当前运行时类中声明的所有方法
Method[] declaredMethods = clazz.getDeclaredMethods();
for (Method m : declaredMethods) {
System.out.println(m);
}
//
}
// 注解信息
// 权限修饰符 返回值类型 方法名(形参类型1 参数1,形参类型2 参数2,...) throws 异常类型1,...{}
@Test
public void test2() {
Class clazz = Person.class;
Method[] declaredMethods = clazz.getDeclaredMethods();
for (Method m : declaredMethods) {
// 1.获取方法声明的注解
Annotation[] annos = m.getAnnotations();
for (Annotation a : annos) {
System.out.println(a);
}
// 2.权限修饰符
System.out.print(Modifier.toString(m.getModifiers()) + "\t");
// 3.返回值类型
System.out.print(m.getReturnType().getName() + "\t");
// 4.方法名
System.out.print(m.getName());
System.out.print("(");
// 5.形参列表
Class[] parameterTypes = m.getParameterTypes();
if (!(parameterTypes == null && parameterTypes.length == 0)) {
for (int i = 0; i < parameterTypes.length; i++) {
if (i == parameterTypes.length - 1) {
System.out.print(parameterTypes[i].getName() + " args_" + i);
break;
}
System.out.print(parameterTypes[i].getName() + " args_" + i + ",");
}
}
System.out.print(")");
// 6.抛出的异常
Class[] exceptionTypes = m.getExceptionTypes();
if (exceptionTypes.length > 0) {
System.out.print("throws ");
for (int i = 0; i < exceptionTypes.length; i++) {
if (i == exceptionTypes.length - 1) {
System.out.print(exceptionTypes[i].getName());
break;
}
System.out.print(exceptionTypes[i].getName() + ",");
}
}
System.out.println();
}
}
}
public class OtherTest {
/*
获取当前类中的所有的构造器
*/
@Test
public void test1(){
Class clazz = Person.class;
Constructor[] cons = clazz.getDeclaredConstructors();
for(Constructor c :cons){
System.out.println(c);
}
}
/*
获取运行时类的父类
*/
@Test
public void test2(){
Class clazz = Person.class;
Class superclass = clazz.getSuperclass();
System.out.println(superclass);//class com.atguigu.java1.Creature
}
/*
获取运行时类的所在的包
*/
@Test
public void test3(){
Class clazz = Person.class;
Package pack = clazz.getPackage();
System.out.println(pack);
}
/*
获取运行时类的注解
*/
@Test
public void test4(){
Class clazz = Person.class;
Annotation[] annos = clazz.getAnnotations();
for (Annotation anno : annos) {
System.out.println(anno);
}
}
/*
获取运行时类所实现的接口
*/
@Test
public void test5(){
Class clazz = Person.class;
Class[] interfaces = clazz.getInterfaces();
for (Class anInterface : interfaces) {
System.out.println(anInterface);
}
}
/*
获取运行时类的父类(带泛型)
*/
@Test
public void test6(){
Class clazz = Person.class;
Type genericSuperclass = clazz.getGenericSuperclass();
System.out.println(genericSuperclass);//com.atguigu.java1.Creature
}
}
@Test
public void test5() throws ClassNotFoundException {
Class clazz = Class.forName("com.xc.data.Person");
//获取带泛型的父类(Type是一个接口,Class实现了此接口
Type superclass = clazz.getGenericSuperclass();
//如果父类是带泛型的,则可以强转为ParameterizedType
ParameterizedType paramType = (ParameterizedType) superclass;
//调用getActualTypeArguments()获取泛型的参数,结果是一个数组,因为可能有多个泛型参数。
Type[] arguments = paramType.getActualTypeArguments();
//获取泛型参数的名称
System.out.println(((Class)arguments[0]).getName()); // java.lang.String
}
在反射机制中,可以直接通过Field类操作类中的属性,通过Field类提供的set()和get()方法就可以完成设置和取得属性内容的操作
(1)获取该类型的Class对象
Class clazz = Class.forName(“包.类名”);
(2)获取属性对象
Field field = clazz.getDeclaredField(“属性名”);
(3)如果属性的权限修饰符不是public,那么需要设置属性可访问
field.setAccessible(true);
(4)创建实例对象:如果操作的是非静态属性,需要创建实例对象
Object obj = clazz.newInstance(); //有公共的无参构造
Object obj = 构造器对象.newInstance(实参…);//通过特定构造器对象创建实例对象
(5)设置指定对象obj上此Field的属性内容
field.set(obj,“属性值”);
如果操作静态变量,那么实例对象可以省略,用null表示(
field.set(null,"属性值")
;)
(6)取得指定对象obj上此Field的属性内容
Object value = field.get(obj);
如果操作静态变量,那么实例对象可以省略,用null表示(
Object value = field.get(null)
;)
示例:
public class TestField {
public static void main(String[] args)throws Exception {
//1、获取Student的Class对象
Class clazz = Class.forName("com.atguigu.reflect.Student");
//2、获取属性对象,例如:id属性
Field idField = clazz.getDeclaredField("id");
//3、如果id是私有的等在当前类中不可访问access的,我们需要做如下操作
idField.setAccessible(true);
//4、创建实例对象,即,创建Student对象
Object stu = clazz.newInstance();
//5、获取属性值
/*
* 以前:int 变量= 学生对象.getId()
* 现在:Object id属性对象.get(学生对象)
*/
Object value = idField.get(stu);
System.out.println("id = "+ value);
//6、设置属性值
/*
* 以前:学生对象.setId(值)
* 现在:id属性对象.set(学生对象,值)
*/
idField.set(stu, 2);
value = idField.get(stu);
System.out.println("id = "+ value);
}
}
关于setAccessible方法的使用:
Java语言访问检查
Java语言访问检查
(1)获取该类型的Class对象
Class clazz = Class.forName(“包.类名”);
(2)获取方法对象
Method method = clazz.getDeclaredMethod(“方法名”,方法的形参类型列表);
(3)创建实例对象
Object obj = clazz.newInstance();
(4)调用方法
Object result = method.invoke(obj, 方法的实参值列表);
如果方法的权限修饰符修饰的范围不可见,也可以调用setAccessible(true)
如果方法是静态方法,实例对象也可以省略,用null代替(Object result = method.invoke(null, 方法的实参值列表)
;)
示例代码:
public class TestMethod {
@Test
public void test()throws Exception {
// 1、获取Student的Class对象
Class<?> clazz = Class.forName("com.atguigu.reflect.Student");
//2、获取方法对象
/*
* 在一个类中,唯一定位到一个方法,需要:(1)方法名(2)形参列表,因为方法可能重载
*
* 例如:void setName(String name)
*/
Method setNameMethod = clazz.getDeclaredMethod("setName", String.class);
//3、创建实例对象
Object stu = clazz.newInstance();
//4、调用方法
/*
* 以前:学生对象.setName(值)
* 现在:方法对象.invoke(学生对象,值)
*/
Object setNameMethodReturnValue = setNameMethod.invoke(stu, "张三");
System.out.println("stu = " + stu);
//setName方法返回值类型void,没有返回值,所以setNameMethodReturnValue为null
System.out.println("setNameMethodReturnValue = " + setNameMethodReturnValue);
Method getNameMethod = clazz.getDeclaredMethod("getName");
Object getNameMethodReturnValue = getNameMethod.invoke(stu);
//getName方法返回值类型String,有返回值,getNameMethod.invoke的返回值就是getName方法的返回值
System.out.println("getNameMethodReturnValue = " + getNameMethodReturnValue);//张三
}
@Test
public void test02()throws Exception{
Class<?> clazz = Class.forName("com.atguigu.ext.demo.AtGuiguClass");
Method printInfoMethod = clazz.getMethod("printInfo", String.class);
//printInfo方法是静态方法
printInfoMethod.invoke(null,"尚硅谷");
}
}
添加注解的类:
@Table("t_stu")
public class Student {
@Column(columnName = "sid",columnType = "int")
private int id;
@Column(columnName = "sname",columnType = "varchar(20)")
private String name;
}
读取和处理自定义注解:
public class AnnotationTest {
//获取类声明上的注解
@Test
public void test1(){
Class clazz = Customer.class;
Table annotation = (Table) clazz.getDeclaredAnnotation(Table.class);
System.out.println(annotation.value());
}
//获取属性声明的注解
@Test
public void test2() throws Exception {
Class clazz = Customer.class;
Field nameField = clazz.getDeclaredField("name");
//获取属性声明上的注解
Column nameColumn = nameField.getDeclaredAnnotation(Column.class);
System.out.println(nameColumn.columnName());//sname
System.out.println(nameColumn.columnType()); //varchar(20)
}
}