package OneDay;
/**
* 1、反射机制有什么用?
* 通过java语言中的反射机制可以操作字节码文件
* 优点类似于黑客(可以读和修改字节码文件)
* 2、反射机制相关类:java.lang.reflect.*;
* 3、相关类:(较重要)
* java.lang.Class; 代表字节码文件,代表一个类型 代表整个类
* java.lang.reflect.Method 代表字节码中的方法字节码 类中的方法
* java.lang.reflect.Constructor 代表字节码中的构造方法字节码 类中的构造方法
* java.lang.reflect.Field 代表字节码中的属性字节码 类中的成员变量(静态变量,实例变量)
* java.lang.Class{
* public class User{
* //Field
* int No;
*
* //Constructor
* public user(){
*
* }
*
* //Method
* public void setNo(int aa){
*
* }
* public int getNo(){
* return No;
* }
* }
*
* }
*
* 4、关于JDK中自带的类加载器:
* 1、什么是类加载器?
* 专门负责加载类的命令/工具
* 2、JDK中自带了3个加载器:
* 启动类加载器
* 扩展类加载器
* 应用类加载器
*
* 3.假设有这样一段代码:String s = "abc"
* 代码在开始执行前,会将所需要类全部加载到JVM当中,通过类加载器加载,看到以上代码类加载器会找String.class
* 文件,找到就加载,怎么进行加载?
* 通过“启动类加载器”加载,启动类加载器专门加载:/jre/lib/rt.jar的文件
* rt.jar是JDK最核心的类库
*
* 如果通过“启动类加载器”加载不到的时候,会通过“扩展类加载器”进行加载
* /jre/lib/ext/*.jar
*
* 如果“扩展类加载器”没有加载到,会通过“应用类加载器”加载
* 专门加载:classpath中的类
*
* java中为了保证类加载的安全,使用了双亲委派机制,优先从启动类加载器中加载,这个称为“父”
* “父”无法加载到,再从扩展类加载器中加载,这个称为“母”,双亲委派,如果都加载不到,才会考虑从
* 应用类加载器中加载,直到加载到为止。
*
*/
public class Note01 {
}
package OneDay;
import java.util.Date;
/*
* 要操作一个类的字节码,首先获取这个类的字节码,怎么获得java.lang.Class实例?
* 三种方式:
* 1、Class c = Class.forName("完整的类名");
* 2、Class c = 对象.getClass();
* 3、Class c = 任何类型.class;
* */
public class ReflectTest01 {
public static void main(String[] args) {
/*
* Class.forName()
* 1、静态方法
* 2、方法的参数是一个字符串
* 3、字符串需要的是一个完整类名
* 4、完整类名必须要带有包名:java.lang包不能省略
* */
Class c = null;
Class d = null;
try {
c = Class.forName("java.lang.String");
d = Class.forName("java.util.Date");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
//java中任何一个对象都有一个方法:getClass()
String s = "abc";
Class ss = s.getClass();//ss代表String.class字节码文件,ss代表String类型
System.out.println(c == ss);
Date time = new Date();
// Class y = time.getClass();
Class y = new Date().getClass();
System.out.println(d == y);
//第三种方式,java语言中任何一种类型,包括基本数据类型,都有.class属性
Class s01 = String.class;
Class s02 = Date.class;
Class s03 = int.class;
Class s04 = double.class;
System.out.println(ss == s01);
}
}
package OneDay;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.Properties;
/*
* 验证反射机制的灵活性:
* java代码写了之后,在不改变java源代码的基础上,可以做到不同对象的实例化,只改配置文件就行,
* 非常之灵活,符合OCP原则,对扩展开放,对修改关闭
*
* 后期学期框架的时候,框架实现原理:都采用了反射机制,
* 所以,理解反射机制对以后剖析框架底层源代码有帮助
* */
public class ReflectTest02 {
public static void main(String[] args) {
//直接创建对象,但是这方式写死了,只能创建一个Student类型的对象
Student student = new Student();
System.out.println(student);
FileReader reader = null;
try {
//通过反射机制,获取class,通过Class实例化对象
Class c = Class.forName("OneDay.Student");//c代表student类型
reader = new FileReader("src/myfile.properties");
//创建属性类对象pro
Properties properties = new Properties();//key,value都是String
//加载
properties.load(reader);
//通过key来获取value
String value = properties.getProperty("user");
System.out.println("value: user = " + value);
//通过反射机制实例化对象
System.out.println("--------------------------------");
Class d = Class.forName("OneDay.Student");
Class cc = Class.forName(value);
Object obj = cc.newInstance();
System.out.println(obj);
System.out.println("--------------------------------");
//newInstance()这个方法会调用student类型的无参构造方法,完成对象的创建
//注意:newInstance调用的是无参构造方法,必须保证无参构造方法是存在的
Object obj01 = c.newInstance();
System.out.println(obj01);
/* 无参构造方法!!!!
OneDay.Student@7ef20235
--------------------------------
Mon Dec 07 18:35:37 CST 2020
--------------------------------
无参构造方法!!!!
OneDay.Student@1b2c6ec2
*/
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
if (reader != null) {
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
package OneDay;
public class Student {
public Student() {
System.out.println("无参构造方法!!!!");
}
}
========================
package TwoDay;
/**
* Class.forName()发生了什么?
* 如果希望一个类的静态代码块执行,其他的代码一律不执行
* 可以使用:
* Class.forName("完整类名")
* 这个方法的执行会导致类加载,类加载时,静态代码块执行
*/
public class ClassForNameTest {
public static void main(String[] args) {
try {
Class.forName("TwoDay.Student01");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
class Student01{
static {
System.out.println("这里是静态代码块,静态代码块执行看!!!");
}
}
package TwoDay;
import java.io.File;
/**
* 研究一下文件路径的问题
*/
public class roadTest01 {
public static void main(String[] args) {
/**
* File reader = new File("myfile");
* 这种方式的路径缺点是:移植性差,在IDEA中默认的当前路径是project的跟
* 这个代码假设离开了IDEA,可能路径就不是project的根了,这是路径就无效了
*
* 注意:使用以下通用方式的前提是:这个文件必须在类路径下
* 什么是类路径?在src下的都是类路径下,src是类的根路径
* (注意:在src下新建个包,在包里创建文件,也可以,不过得从src路径开始,如TwoDay/myfile02)
*
* Thread.currentThread() 当前线程对象
* getContextClassLoader() 是线程对象的方法,可以获取当前线程的类加载器对象
* getResource() 获取资源,这是类加载器对象的方法,当前线程的类加载器默认从类的根路径下加载资源
*
*/
// 这种方式获取文件的路径是通用的,可以跨系统,如Linux系统(没有盘符),也是可以的
String str = Thread.currentThread().getContextClassLoader().
getResource("myfile").getPath();
System.out.println(str);
// /I:/project/java%e8%bf%9b%e9%98%b6/18.%e5%8f%8d%e5%b0%84/Test/out/test/Test/myfile
String str02 = Thread.currentThread().getContextClassLoader().
getResource("TwoDay/myfile02").getPath();
System.out.println(str02);
/// I:/project/java%e8%bf%9b%e9%98%b6/18.%e5%8f%8d%e5%b0%84/Test/out/test/Test/TwoDay/myfile02
}
}
package TwoDay;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
public class IoPropertiesTest {
public static void main(String[] args) {
//这里有问题,找不到文件,原来是中文的问题
/* String path = Thread.currentThread().getContextClassLoader().
getResource("TwoDay/myfile02").getPath();
FileReader reader = null;*/
InputStream reader = null;
//返回一个流
try {
/*reader = new FileReader(path);*/
reader = Thread.currentThread().getContextClassLoader().
getResourceAsStream("TwoDay/myfile02");
Properties pro = new Properties();
pro.load(reader);
System.out.println(pro.getProperty("vip02"));
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (reader != null) {
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
=====================================
package ThreeDay;
import java.util.ResourceBundle;
/**
* java.util包下提供了一个资源绑定器,便于获取属性配置文件中的内容
* 使用以下这种方式的时候,属性配置文件***.properties必须放到类路径下(以src为起点)
* 注意:这种方式相当于取代了IO+properties
*/
public class ResourceBundleTest {
public static void main(String[] args) {
//资源绑定器,只能绑定***.properties文件,并且这个文件必须在类路径下,文件拓展名也必须是properties
//并且在写路径的时候,路径后面的扩展名不用写
ResourceBundle boudle = ResourceBundle.getBundle("myfile");
String str = boudle.getString("user");
String str11 = boudle.getString("vip");
System.out.println("user = " + str);
System.out.println("vip = " + str11);
ResourceBundle resourceBundle = ResourceBundle.getBundle("ThreeDay/three");
String str01 = resourceBundle.getString("password");
String str02 = resourceBundle.getString("user");
System.out.println("password = " + str01);
System.out.println("user = " + str02);
}
}
==================================
package fourDay;
//通过反射机制,反编译一个类的属性field,给我一个class文件,我可以拿到你的源码
//的确很强大
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
public class FanBianYiTest {
public static void main(String[] args) {
//创建一个字符串拼接对象,使用于频繁拼接字符串时
StringBuilder ss = new StringBuilder();
try {
Class student = Class.forName("java.lang.String");
ss.append(Modifier.toString(student.getModifiers()) + " class " + student.getSimpleName() + "{\n");
Field[] fields = student.getDeclaredFields();
for (Field field : fields){
ss.append("\t");
ss.append(Modifier.toString(field.getModifiers()));
ss.append(" ");
ss.append(field.getType().getSimpleName());
ss.append(" ");
ss.append(field.getName());
ss.append("\n");
}
ss.append("}");
System.out.println(ss);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
package fourDay;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
public class ReflectTest {
public static void main(String[] args) {
//获取整个类
//疑问:为什么不用File,用class呢,因为不方便,fileReader后,返回的一个flie文件
//File主要使用来读文件的,class返回后可以获取名字,长度,还可以遍历里面的属性,修饰符
try {
FileReader aa = new FileReader("fourDay.Student");
Class studentClass = Class.forName("fourDay.Student");
String className = studentClass.getName();
System.out.println(className);
//获取类中所有public修饰的field
Field[] files = studentClass.getFields();
System.out.println("getFields.length测试数组中有几个元素:" + files.length);
//取出这个Field
Field file = files[0];
//取出他的名字
System.out.println(file.getName());
//获取所有的Field
Field[] fs = studentClass.getDeclaredFields();
System.out.println("getDeclaredFields()获取的Field[]对象长度:" + fs.length);
System.out.println("----------------");
//遍历
for(Field field : fs){
//获取属性的类型名
Class fieldTypes = field.getType();
String fieldTypesName = fieldTypes.getName();
System.out.println("属性的类型名:" + fieldTypesName);
System.out.println("属性的类型名(简单实现):" + fieldTypes.getSimpleName());
//获取属性的修饰符,返回的是一个数字,修饰符的代号
int i = field.getModifiers();
System.out.println("修饰符的代号 :" + i);
String str = Modifier.toString(i);
System.out.println("修饰符:" + str);
System.out.println(field.getName());
}
} catch (ClassNotFoundException | FileNotFoundException e) {
e.printStackTrace();
}
}
}
package fourDay;
public class Student {
protected int age;
private String name;
public String sex = "nan";
boolean man ;
public static final double PI = 3.122323;
}
============================
package five;
/**
* 可变长度参数,int...args 可变长度参数,类型一定是三个点...
* 1、参数个数是0-N个
* 2、可变长度参数必须是最后一个,只能出现一个
* 3、可变长度参数可以当做一个数组来看待
*/
public class ArgsTest {
public static void main(String[] args) {
m();
s(12, "egtr", "sadvf");
ss("aa", "abb", "afda");
ss(new String[]{"ad", "ads", "asdf", "adf"});
ss("发不发","绍飞表达式","是人更");
}
public static void m(int... args) {
System.out.println("无参方法执行");
}
//可变长度参数必须是最后一个,只能出现一个
/*public static void s(String...args,int...args){
}*/
public static void s(int i, String... args) {
System.out.println("==============");
System.out.println(i + args[0] + " " + args[1]);
System.out.println(args);
System.out.println("==============");
}
//可变长度参数可以当做一个数组来对待
public static void ss(String... args) {
for (int i = 0; i < args.length; i++) {
System.out.print(args[i] + " ");
}
}
}
package five;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
public class ReflectConstructorCreate {
public static void main(String[] args) {
try {
Class user = Class.forName("five.User");
//构造方法创建无参的对象
Object obj = user.newInstance();
System.out.println("无参构造:" + obj);
//创建有参的对象
//先获得有参的构造方法
Constructor constructor = user.getConstructor(String.class,int.class);
Constructor constructor1 = user.getConstructor(String.class);
Constructor constructor2 = user.getConstructor(String.class,int.class,double.class);
Constructor constructor3 = user.getConstructor();
//主要方法
Object obj1 = constructor.newInstance("miao",123);
Object obj2 = constructor1.newInstance("mmn");
Object obj3 = constructor2.newInstance("mmm",132,123.9);
Object obj4 = constructor3.newInstance();
System.out.println(obj1);
System.out.println(obj2);
System.out.println(obj3);
System.out.println(obj4);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
package five;
import java.lang.reflect.Constructor;
import java.lang.reflect.Modifier;
/**
* 反射获取构造方法.
*/
public class ReflectConstructorTest {
public static void main(String[] args) {
try {
//获取字节码类
Class user = Class.forName("five.User");
//获取构造方法
Constructor[] constructors = user.getConstructors();
for(Constructor constructor : constructors){
StringBuilder ss = new StringBuilder();
ss.append("\t");
//修饰符
ss.append(Modifier.toString(constructor.getModifiers()));
ss.append(" ");
//注意:构造方法没有数据类型,这里获取类名
ss.append(user.getSimpleName());
//形参
ss.append("(");
/**
* 注意这种方式是错误的
* Parameter[] parameters = constructor.getParameters();
* public User(arg0arg1arg2){}错误的输出
* 这种方式获取的是形参个数对上了,但形参类型没有输出
*
* 这种是正确的
* Class[] parameters = constructor.getParameterTypes();
*/
Class[] parameters = constructor.getParameterTypes();
for( Class parameter : parameters){
ss.append(parameter.getSimpleName());
ss.append(",");
}
if(parameters.length > 0){
ss.deleteCharAt(ss.length() - 1);
}
ss.append("){\n}");
System.out.println(ss);
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
package five;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/**
* 重点:怎么通过反射机制调用一个对象的方法?
*
* 1、获取类名 Class.forName("");
* 2、创建对象 .newInstance();
* 3、获得方法 Method ff = user.getMethod("dengLu",String.class,int.class);
* 4、调用方法 ff.invoke(obj,"miao",123);
* 重点:::invoke方法调用
*
* 反射机制让代码更具有通用性,可变化的内容都是写到配置文件中
* 将来修改配置文件之后,创建的对象不一样了,调用的方法也不同了
* 但是java代码不需要做任何改动
* 但是现在还没有体会到
*
*/
public class ReflectDiaoYongMethod {
public static void main(String[] args) {
try {
//获取类名
Class user = Class.forName("five.User");
//创建对象
Object obj = user.newInstance();
//获取方法
// 调用方法四要素:
//方法,对象,实参,返回值
Method userMethod = user.getMethod("dengLu", String.class,int.class);
Object retValue = userMethod.invoke(obj,"miao",21);
System.out.println(retValue);
// master认证成功!!!欢迎回来!!
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
package five;
//重点:给你一个类,怎么获取这个类的父类,已经实现了哪些接口?
public class ReflectFuLeiJieKou {
public static void main(String[] args) {
try {
Class string = Class.forName("java.lang.String");
Class stringParent = string.getSuperclass();
System.out.println("获取String的父类 : " + stringParent);
Class[] inter = string.getInterfaces();
System.out.println("获取string的接口:" + inter);
for(Class jieKou : inter){
System.out.println("遍历接口 :" + jieKou.getName());
}
/**
* 获取String的父类 : class java.lang.Object
* 获取string的接口:[Ljava.lang.Class;@7b23ec81
* 遍历接口 :java.io.Serializable
* 遍历接口 :java.lang.Comparable
* 遍历接口 :java.lang.CharSequence
* 遍历接口 :java.lang.constant.Constable
* 遍历接口 :java.lang.constant.ConstantDesc
*/
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
package five;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
public class ReflectMethodTest {
public static void main(String[] args) {
try {
Class string = Class.forName("java.lang.String");
//获取所有的方法Method(所有的方法包括私有的)
Method[] methods = string.getMethods();
System.out.println("String 方法的个数:" + methods.length);
//遍历这些方法
for (Method method : methods) {
StringBuilder aa = new StringBuilder();
//修饰符
aa.append(Modifier.toString(method.getModifiers()));
aa.append(" ");
//返回值类型
aa.append(method.getReturnType().getSimpleName());
aa.append(" ");
//方法名,这个没有SimpleName,方法没有简称
aa.append(method.getName());
//形参
aa.append("(");
Class[] parameterTypes = method.getParameterTypes();
for (Class parameterType : parameterTypes){
aa.append(parameterType.getSimpleName());
aa.append(",");
}
if(parameterTypes.length > 0){
aa.deleteCharAt(aa.length() - 1);
}
aa.append(")");
aa.append(" {\n}");
System.out.println(aa);
}
/**
* String 方法的个数:90
* public boolean equals(Object) {
* }
* public int length() {
* }
* public String toString() {
* }
* public int hashCode() {
* }
* public void getChars(int,int,char[],int) {
* }
* public volatile int compareTo(Object) {
* }
*/
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
package five;
import java.lang.reflect.Field;
/**
* 反射属性field
* 怎么通过反射机制访问一个java对象的属性?
* 给对象属性赋值
* 获取对象属性
*
*/
public class Test {
public static void main(String[] args) throws IllegalAccessException, InstantiationException, ClassNotFoundException {
//使用反射机制怎样访问一个对象的属性
Class student = Class.forName("fourDay.Student");
Object obj = student.newInstance();
//obj就是Student对象(底层调用无参构造方法)
//获取sex属性(根据属性的名称获取field)
try {
Field field = student.getDeclaredField("sex");
//给Obj(student对象)的sex属性赋值,可以等同看做sex.set(obj,"nan") 个Obj的sex进行赋值,只是形式有些不是常规的
field.set(obj,"nan");
//获取Obj对象的age的值,这个地方为什么直接获取的是对象属性的值?而不是对象的内存地址?
//答:这个是不是可以看做,sex.get(obj) 获取Obj对象的sex属性
System.out.println(field.get(obj));
/**
* 注意修饰符,protected,private,默认访问不了
* 打破封装就可以访问了
* 缺点:打破封装,可能会给不法分子留下机会
*
*/
Field field1 = student.getDeclaredField("name");
field1.setAccessible(true);
Object obj1 = student.newInstance();
field1.set(obj1,"miao");
System.out.println(field1.get(obj1));
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
package five;
public class User {
private String name;
private int age;
private double balance;
public User(String name) {
this.name = name;
}
public User(String name, int age) {
this.name = name;
this.age = age;
}
public User(String name, int age, double balance) {
this.name = name;
this.age = age;
this.balance = balance;
}
public User() {
}
public String dengLu(String name,int age){
if(name.equals("miao") && age == 21){
return "master认证成功!!!欢迎回来!!";
}
return "master认证失败";
}
@Override
public String toString() {
return " name:" + name +
" age:" + age +
" balance:" + balance;
}
}