# 01 Class类 (3种实现方式)
## 一、反射
> 1、java反射机制就是在程序运行状态中,对于任意一个类,都能够知道这个类的属性和方法;对于任意一个对象,都能够调用到他的属性和方法。这种动态获取信息以及动态调用对象的方法的功能称为java语言的反射机制。
> 2、Class类的使用
> 3、方法的反射
> 4、成员变量的反射
> 5、构造函数的反射
> 6、Java类加载机制
## 二、Class类
> 1、万事万物皆为对象
> `那么类是谁的对象?`
> 类是对象,类是Java.lang.Class的实例对象这个对象称为该类的类类型
> 2、如创建一个Person类,创建一个实挒对象
```java
//Person的实挒对象 person表示出来了
Person person = new Person();
```
### 1、那么Person这类是一个实挒对象,也是一个Class类的实挒对象怎么表示?
> 1、3种表示,`注意:Class有私有的构造方法,外部是无法访问的`
```java
//Class类的源码 私有的构造方法
private Class(ClassLoader loader) {
// Initialize final field for classLoader. The initialization value of non-null
// prevents future JIT optimizations from assuming this final field is null.
classLoader = loader;
}
```
#### 一种、类名.Class
```
//如实挒我们知道任何一个类都有一个隐藏的静态成员变量class Class cp=Person.class;
```
#### 一种、该类的对象.getClass();
```java
//已经知道该类的对象可以通过getClass方法
Class cp1 = person.getClass();
在这里就能把cp cp1说层是Person类的类类型
```
#### 一种、Class.forName("该的路径");
```java
Class cp3=null;
try {
cp3=Class.forName("com.reflect.project.entity.Person");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
```
> 1、但是一个类只能是Class类一个实挒对象
> 如下结果都为`true`
```java
System.out.println(cp==cp1);//true
System.out.println(cp==cp3);//true
```
### 2、通过反射怎么获取方法?
```java
try {
Person newInstance = (Person) cp1.newInstance();
//可以调用无参数的构造方法 前提必须有无参数的构造方法
newInstance.getPerson();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
```
# 02 Class类动态加载类的用法
## Class类动态加载类的用法
### 一、Class.forName("类的路径")
> 1、不仅表示了类的类型,还表示了动态加载类
> 在这里要区分编译 和 运行
> 编译时加载类是静态加载类
> 运行时加载类是\*动态加载类
### 1、静态加载类
> 1、new 创建对象 是静态加载类,在编译时刻就需要加载可能使用到的类
> `问:那么我们能不能在使用到类就进行加载?`
> `答:使用动态加载类就可以完成`
```java
Teacher teacher = new Teacher();
Student Student = new Student();
```
### 2、动态加载类
> 1、Teacher 和 Student 类必须实现 Person接口 并重写start()方法
```java
//接口
public interface Person {
public void start();
}
测试
@Test
public void getTest(){
try {
Class forName = Class.forName("com.reflect.project.entity.Student");
Person newInstance = (Person) forName.newInstance();
newInstance.start();
} catch (Exception e) {
e.printStackTrace();
}
}
```
# 03 Class类的使用
## Class类的使用
### 一、基本的数据类型的类类型
```java
@Test
public void getTest1(){
//可以说int的类类型
Class in= int.class;
//可以说String的类类型
Class str= String.class;
//dou 和 dou1不一样
Class dou= double.class;//double数据类类型
Class dou1=Double.class;//Double类类型
//打印类的名称
System.out.println(str.getName());
System.out.println(dou .getName());
//获取父类
System.out.println(dou.getSuperclass().getName());
//不包含包名的类名称
System.out.println(dou1.getSimpleName());
}
```
# 05 Class类API 获取成员变量的信息
## 一、Class类获取方法信息
### 1、获取类的全名称
```java
@Test
public void getTest2(){
Class stClass= Student.class;
//获取类全名称
System.out.println("获取类全名称>>"+stClass.getName());
}
```
### 2、获取返回值 方法名 参数
```
一个成员方法就是一个Method对象
```
> 1、getMethods()方法是获取所有Public 修饰的方法,包括父类的
> 2、getDeclaredMethods()获取的是所有本类声明的方法,不包括父类的
> `获取返回值 方法名 参数`
```java
@Test
public void getTest2() {
Class stClass = String.class;
Method[] methods = stClass.getMethods();
for (int i = 0; i < methods.length; i++) {
// 获取方法的返回值类型的类类型
Class returnType = methods[i].getReturnType();
System.out.print(returnType.getName() + " ");
// 获取方法的名称
System.out.print(methods[i].getName() + "(");
// 获取参数的类型-->参数列表的类型的类类型
Class[] parameterTypes = methods[i].getParameterTypes();
for (Class class1 : parameterTypes) {
System.out.print(class1.getName() + " ");
}
System.out.print(")");
System.out.println();
}
}
```
# 06 Class类API 获构造函数的信息
## 一、获构造函数的信息
> 1、构造函数方法对象java.lang.reflect.Constructor
> 2、getConstructors()获取所有的public的构造函数
> 3、getDeclaredConstructors获取是该类声明的构造函数
### 1、获取构造函数的参数列表--得到的是参数列表的类类型
```java
@Test
public void getTest4() {
Class stClass = String.class;
Constructor[] constructors = stClass.getConstructors();
Constructor[] declaredConstructors = stClass.getDeclaredConstructors();
for (Constructor constructor : declaredConstructors) {
System.out.print(constructor.getName()+"(");
//获取构造函数的参数列表--得到的是参数列表的类类型
Class[] parameterTypes = constructor.getParameterTypes();
for (Class class1 : parameterTypes) {
System.out.print(class1.getName());
}
System.out.print(")");
System.out.println();
}
}
```
### 2、获取指定的构造函数
```java
@Test
public void getTest7(){
/**
* 获取带两个参数(String,int)的构造方法
* */
Class personClass = Student.class;
try {
Constructor constructor =personClass.getConstructor(String.class,int.class);
//需要强制转换
Student per =(Student)constructor.newInstance("小张",23);
System.out.println(per);
} catch (Exception e) {
e.printStackTrace();
}
}
```
# 07 Class类API 获取某一个方法的反射
## 一、获取某一个方法的反射
> 1、方法的操作 method.invoke(对象,参数列表)
> 2、获取方法 由名称和参数列表类决定
> 3、getMethod(name, parameterTypes) 获取的public的方法
> 4、getDeclaredMethod(name, parameterTypes) 获取自己声明的方法
### 1、获取带参数的方法
```java
@Test
public void getTest5() {
Student Student = new Student();
Class stClass = Student.getClass();
try {
//这两种方法都可使用
System.out.println("----------一种---------------");
Method method = stClass.getMethod("start",new Class[]{int.class,int.class});
//如有返回就返回的对应的返回值,没有则为null
Object invoke = method.invoke(Student, new Object[]{1,2});
System.out.println(invoke);
System.out.println("----------二种---------------");
Method method1 = stClass.getMethod("start",String.class,String.class);
Object invoke2 = method1.invoke(Student, "小张","小组");
System.out.println(invoke2);
} catch (Exception e) {
e.printStackTrace();
}
}
```
### 2、获取无参数的方法
```java
@Test
public void getTest5() {
Student Student = new Student();
Class stClass = Student.getClass();
try {
System.out.println("----------一种---------------");
Method method4 = stClass.getMethod("start");
Object invoke4 = method4.invoke(Student);
System.out.println(invoke4);
System.out.println("----------二种---------------");
Method method3 = stClass.getMethod("start", new Class[]{});
Object invoke3 = method3.invoke(Student);
System.out.println(invoke3);
} catch (Exception e) {
e.printStackTrace();
}
}
```
# 08 Class类API 通过反射越过泛型
## 一、通过反射越过泛型
> 1、泛型在编译之后会去掉泛型
> 2、集合的泛型只是在输入的时候生效,而在编译的时候有效
> 3、通过反射的方式越过泛型,就可进行添加值
```java
@Test
public void getTest6(){
ArrayList<String> array=new ArrayList<String>();
array.add("小张");//只能输入String类型的
ArrayList array1=new ArrayList();
array1.add(11);
Class ca1=array1.getClass();
Class ca=array.getClass();
System.out.println(ca1==ca);
/**
* ca1==ca为true 说明集合的泛型只是在输入的时候生效,而在编译的时候有效
* 越过编译就无效了
* */
//反射进行越过泛型
try {
Method method = ca.getMethod("add", Object.class);
method.invoke(array, 123);
//array 中有字符串和数字 方式泛型是String(反射越过泛型)
System.err.println(array);
} catch (Exception e) {
e.printStackTrace();
}
}
```