反射
耦合度:多个模块之间的关联或者依赖关系(低耦合)
解析类:用于找到字节码对象以产生实例对象的过程—反射
Class------代表类的类----代表.class的类
Field—代表属性的类
Method—代表方法的类
Construct----代表构造方法的类
Annotation—代表注解的类
Package----代表包的类
获取字节码对象的方式
1、通过类名.class获取字节码对象
2、通过对象.getclass获取对象实际创建类的字节码对象
3、Class.forName(全路径名)—获取类的字节码对象
反射的缺点
1、打破封装的原则
2、跳过泛型的类型检测
package cn.tedu.classx;
import java.util.List;
public class ClassDemo1 {
public static void main(String[] args) throws ClassNotFoundException {
//获取String的字节码对象
//1、类名.class
Class<String> clz1=String.class;
//接口的字节码对象
Class<List> clz2=List.class;
//基本类型的字节码对象
Class clz3=int.class;
//2、对象.getClass
String str="abc";
Class<String> clz=(Class<String>) str.getClass();
//通知对象获得integer的字节码对象
Integer in=12;
Class<Integer> clz4=(Class<Integer>) in.getClass();
//3、Class.forName(全路径名)---获取到对应的字节码对象
Class clz5=Class.forName("java.util.Date");
System.out.println(clz5);
}
}
public class ClassDemo2 {
public static void main(String[] args) throws Exception {
//先获取String的字节码对象
Class <String> clz=String.class;
/*//获取实例对象
//newInstance()---默认在调用类的无参构造
String str=clz.newInstance();
str="abc";
System.out.println(str);*/
//通过字节码对象调用到String类的有参构造
Constructor c=clz.getConstructor(char[].class);//传入构造方法参数类型的字节码对象
//获取到的有参构造调用newInstance()传入实际参数构造实例对象
String str=(String)c.newInstance(new char[] {'1','2','a'});
//获取构造方法
Constructor c1=clz.getConstructor(String.class);
//传参---构建实例对象
String str1=(String) c1.newInstance("abc");
//通过Integer的全路径名获取integer的实例对象并赋值
//通过class.forname()获取字节码对象
Class<Integer> clz1=(Class<Integer>) Class.forName("java.lang.Integer");
//获取有参构造方法new Integer(int)
Constructor c2=clz1.getConstructor(int.class);
//传参--构建实例对象
Integer in=(Integer) c2.newInstance(123);
System.out.println(in);
}
}
构造方法的类
public class ClassDemo3 {
public static void main(String[] args) throws NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
//获取字节码对象
Class<String> clz=String.class;
/*//获取构造方法
//Constructor c=clz.getConstructor(char[].class,boolean.class);//报错不可用
//获取指定的构造方法(忽略访问权限修饰符)
Constructor c=clz.getDeclaredConstructor(char[].class,boolean.class);
//暴力破解(可以操作特殊的构造方法)
c.setAccessible(true);
//传参,构建实例对象
String str=(String) c.newInstance(new char[] {'2'},true);
System.out.println(str);*/
//获取String类里的所有构造方法
Constructor[] cs=clz.getDeclaredConstructors();
for (Constructor constructor : cs) {
System.out.println(constructor);
}
}
}
属性的类
public class ClassDemo4 {
public static void main(String[] args) throws Exception {
//String的字节码对象
Class<String> clz=String.class;
//获取指定的属性--hash
Field f=clz.getDeclaredField("hash");
//暴力破解
f.setAccessible(true);
//字符串对象--属性
String str="abc";
/*//给对象的属性赋值--给Str对象的hash属性赋值为123
f.set(str, 123);
//取值---获取Str对象的hash属性的值
System.out.println(f.get(str));
System.out.println(str.hashCode());*/
//获取字符串的所有属性
Field[] fs=clz.getDeclaredFields();
for (Field field : fs) {
System.out.println(field);
}
}
}
属性的类
public class ClassDemo5 {
public static void main(String[] args) throws Exception {
//获取字节码对象
Class<String> clz=String.class;
//获取指定的方法
Method m=clz.getDeclaredMethod("charAt", int.class);
String s="sfasffsdf";
//调用方法---s.charAt(3)
char c=(char) m.invoke(s, 3);
System.out.println(c);
}
}
public class ClassDemo6 {
public static void main(String[] args) {
/*//枚举类的字节码对象
Class<Demo> clz=Demo.class;
//返回枚举常量
Demo[] ds=clz.getEnumConstants();
for (Demo demo : ds) {
System.out.println(demo);
}*/
//
Class<String> clz=String.class;
//没有枚举常量返回的是一个null
//String[]ss=clz.getEnumConstants();
/*//返回的是实现的接口
Class[] cs=clz.getInterfaces();
for (Class class1 : cs) {
System.out.println(class1);
}*/
//字节码对象对应类的全路径名
//System.out.println(clz.getName());
//返回字节码对象对应类的包的名称
//System.out.println(clz.getPackage());
//字节码对象对应类的类名
System.out.println(clz.getSimpleName());
//得到父类的字节码对象
System.out.println(clz.getSuperclass());
}
}
//
enum Demo{
A,B,C,D;//枚举常量,对象
}
public class FiledDemo {
public static void main(String[] args) throws Exception {
//获取字节码对象
Class<String> clz=String.class;
//可以获取指定的属性
Field f=clz.getDeclaredField("serialVersionUID");
//返回属性的数据类型
System.out.println(f.getType());
}
}
public class MethodDemo {
public static void main(String[] args) throws NoSuchMethodException, SecurityException {
Class<String> clz=String.class;
//获取指定的方法
//Method m=clz.getDeclaredMethod("getBytes", String.class);
Method m=clz.getDeclaredMethod("getBytes", Charset.class);
/*//返回的是编译时的异常
Class[] cs=m.getExceptionTypes();
for (Class class1 : cs) {
System.out.println(class1);
}*/
//获取参数类型的字节码放到一个数组
Class[] cs=m.getParameterTypes();
for (Class class1 : cs) {
System.out.println(class1);
}
}
}
public class ClassDemo7 {
public static void main(String[] args) throws Exception {
List<String> list=new ArrayList<String>();
list.add("abc");
//获取list接口字节码对象
Class<List> clz=(Class<List>) list.getClass();
//获取指定的方法
Method m=clz.getDeclaredMethod("add", Object.class);
//调用方法
m.invoke(list, 123);
System.out.println(list);
}
}
反射克隆
package cn.tedu.reflect;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
/**
*@author 作者:
*@version 创建时间:2020年11月30日下午10:36:01
*@description 描述:通过反射实现克隆
*/
public class ReflectText {
public static void main(String[] args) throws Exception {
Person p1=new Person("lili",10);
/*p1.name="lili";
p1.age=10;*/
Person p2=(Person)clone(p1);
System.out.println(p2.name+","+p2.age);
}
//实现Clone方法
public static Object clone(Object obj) throws Exception {
/*//1、获取字节码对象
Class<Object> clz=(Class<Object>) obj.getClass();
//2、获取实例对象--新对象
Object o1=clz.newInstance();
//3、获取原对象的所有属性
Field[] fs=clz.getDeclaredFields();
//4、把原对象的属性赋值给新对象
for (Field f : fs) {
//暴力破解
f.setAccessible(true);
//获取元素对象的属性
Object o2=f.get(obj);
//所有属性赋值给新对象
f.set(o1, o2);
}
//5、返回新对象
return o1;*/
//1、获取字节码对象
Class<Object> clz=(Class<Object>) obj.getClass();
//2、获取构造方法--保证一定能拿到构造方法
Constructor c=clz.getDeclaredConstructors()[0];
//返回拿到的这个构造方法上所有的参数类型的字节码对象
Class[] cs=c.getParameterTypes();//String int
//Object的数组
Object[] os=new Object[cs.length];//null 0
//遍历参数类型的数组
for (int i = 0; i < cs.length; i++) {
//判断参数类型是否是基本类型
if(cs[i].isPrimitive()) {
//
if(cs[i]==byte.class||cs[i]==short.class||cs[i]==int.class) {
os[i]=0;
}
if(cs[i]==char.class){
os[i]='\u0000';
}
if(cs[i]==long.class) {
os[i]=0L;
}
if(cs[i]==float.class) {
os[i]=0.0F;
}
if(cs[i]==double.class){
os[i]=0.0;
}
if(cs[i]==boolean.class) {
os[i]=false;
}
}else {//引用类型
os[i]=null;
}
}
//2、获取实例对象--新对象
Object o1=c.newInstance(os);
//3、获取原对象的所有属性
Field[] fs=clz.getDeclaredFields();
//4、把原对象的属性赋值给新对象
for (Field f : fs) {
//暴力破解
f.setAccessible(true);
//获取元素对象的属性
Object o2=f.get(obj);
//所有属性赋值给新对象
f.set(o1, o2);
}
//5、返回新对象
return o1;
}
}
class Person{
String name;
int age;
public Person(String name, int age) {
super();
this.name = name;
this.age = age;
}
}
注解:
给计算机看的注释
注解属性默认被public static final共同修饰
支持的属性类型–基本数据类型、String、Class、Annotation、枚举以及对应形式的一维数组表现i形式
元注解:
用于控制、限制注解的使用情况(给注解的注释)
@Target—控制注解可以在什么位置使用
@Retention—控制注解的级别
@Documented—可以让注解随着类一起文档化出去
@Inherited—可以让子类依然具有注解
package cn.tedu.annox;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
*@author 作者:
*@version 创建时间:2020年12月3日下午8:19:50
*@description 描述:自定义注释
*/
@First()
public class AnnoDemo1 {
@First()
int i=1;
@First()
public static void main(@First()String[] args) {
@First()
int j=10;
System.out.println(First.i);//First.i=10报错
}
}
/*@First(d=1.2,arr= {1,2,2})
public class AnnoDemo1 {
@First(d=1.2,arr= {1,2,2})
int i=1;
@First(d=1.2,arr= {1,2,2})
public static void main(@First(d=1.2,arr= {1,2,2})String[] args) {
@First(d=1.2,arr= {1,2,2})
int j=10;
System.out.println(First.i);//First.i=10报错
}
}*/
//自定义注释
//@Target(ElementType.TYPE)
//@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.SOURCE)
@Inherited
@interface First{
//默认被public static final共同修饰
public static final int i=10;
//double d();//申明属性没有赋值
//Object类型不在支持的范围之内
//Object od;
//int[] arr();//一维数组
}
生成注释文档
步骤:
project–generate javadoc–选包选Java文件–(D:\Program Files\Java\jdk1.8.0_241\bin\javadoc.exe)
package cn.tedu.annox;
import java.lang.annotation.Documented;
@Documented
public @interface Third {
}
package cn.tedu.annox;
@Third
public class AnnoDemo2 {
public static void main(String[] args) {
}
}
单例设计模式
一个类只能产生一个实例对象
饿汉式:直接生成本类对象
懒汉式:需要调用对象时才生成对应的对象,但是会存在多线程并发安全
去了解其它单例模式的实现方式
package cn.tedu.singlex;
/**
*@author 作者:
*@version 创建时间:2020年12月3日下午9:45:23
*@description 描述:
*/
public class SingleDemo {
public static void main(String[] args) {
//外界可以获取唯一的对象
//TaskManager tm=TaskManager.getInstance();//饿汉式和懒汉式
}
}
//任务管理器---只能创建一个对象
/*//饿汉式实现方式
class TaskManager{
//构造方法私有化
private TaskManager() {}
//创建对象
private static TaskManager tm=new TaskManager();
//给外界获取的方法
public static TaskManager getInstance() {
return tm;//把唯一一个对象进行返回
}
//调用这个静态方法对象就会创建
public static void m() {}
}*/
/*//懒汉式实现方式
class TaskManager{
//构造方法私有化
private TaskManager() {}
//创建对象
private static TaskManager tm=null;
//给外界获取的方法
public static TaskManager getInstance() {
//判断对象是否为null
if(tm==null) {//没有创建过对象
tm=new TaskManager();//创建唯一的对象
}
return tm;
}
//调用这个静态方法对象就会创建
public static void m() {}
}*/
//枚举实现方式
enum TaskManager{
tm;
}
JVM参数
栈:用于计算的 是被线程单独使用的
堆:存储的时对象 是被所有线程共享的
方法区:原名永久代 方法区挪到堆里 存储的是类的所有信息 被所有的线程共享
本地方法栈:用于计算本地方法 被线程单独使用
PC计数器:用于存储计算机/程序的指令以及调度 被线程单独使用
-X 参数—标准参数
-Xxxx 参数—非标准参数
-Xss 128KB—指定的是栈内存的大小
-Xmx 10M–对应的是最大内存的大小
-XX:+PrintGCDetails—指明GC执行的详细细节
package cn.tedu.jvm;
/**
*@author 作者:
*@version 创建时间:2020年12月3日下午10:11:17
*@description 描述:
*/
/*
* 右键run as----run configurations---arguments---vm arguments输入-Xss 128KB--指定占内存的大小
*/
public class JVMDemo {
static int count=0;
public static void main(String[] args) {
sum(100000);
int[] arr=new int[1024*1024*10];
}
public static int sum(int n) {
System.out.println(count++);
if(n==1) {
return 1;
}
return sum(n-1)+n;
}
}
步骤:右键run as----run configurations—arguments—vm arguments输入-Xss 128KB–指定占内存的大小
windows 操作界面 输入java -X(相关详细内容)