反射
类对象:
类加载的产物,封装了一个类的所有信息(类名、父类、接口、属性、方法、构造方法) 。
每个类加载到内存都会生成一个唯一的类对象。
获取类对象的三种方式:
- 通过对象的getClass方法(必须有类的对象,不常用)
- 通过类的Class属性-> 类名.class(多用于方法传参)
- 通过Class类的forName方法传入类的全限定名
Class对象的常用方法:
- getSimpleName() 获取类名
- getName() 获取类的全限定名
- getSuperclass(); 获取父类的类对象
- getInterfaces(); 获取所有父接口的类对象,返回数组
- newInstance(); 通过类对象创建类的对象【这个类必须有无参构造,如果访问权限不够需使用暴力反射】
Field类表示类对象中的属性
Constructor类表示类对象中的构造方法
Method类表示类对象的方法
getDeclared-Field(s)-Constructor(s)-Method(s)可以获取到对应的所有包括私有(属性,构造,方法)
getModifiers()-判断修饰符(1为public,2为private)
设计模式
工厂模式
开发中有一个原则:“开闭原则”-对拓展开放,对修改关闭
工厂模式主要负责对象创建的问题
可通过反射进行工厂模式的设计,完成动态对象的创建
public class Demo03 {
public static void main(String[] args) {
Wife daWife = (Wife) BeanFactory2.getWife("dalaopo");
daWife.sleep();
Wife xiaoWife = (Wife) BeanFactory2.getWife("xiaolaopo");
xiaoWife.sleep();
Wife mnWife = (Wife) BeanFactory2.getWife("mnlaopo");
mnWife.sleep();
}
}
class BeanFactory2{
//存入所有需要创建的类的对象
static Map<String,Object> map =new HashMap<>();
static {
//加载配置文件
Properties properties =new Properties();
try {
//调用ResourceAsStream流读取文件bean.properties将k,V写入properties集合内
properties.load(BeanFactory2.class.getClassLoader().getResourceAsStream("bean.properties"));
//读取properties内所有键值对
Set<Map.Entry<Object, Object>> entries = properties.entrySet();
//根据properties内key对应值(要创建的类的全限定名)通过反射创建对应类的对象并存入静态map表中
for (Map.Entry<Object, Object> entry: entries) {
map.put((String) entry.getKey(),Class.forName((String)entry.getValue()).newInstance());
}
} catch (Exception e) {
e.printStackTrace();
}
}
public static Object getWife(String name){
return map.get(name);
}
}
interface Wife{ void sleep();}
class aWife implements Wife{
@Override
public void sleep() {
System.out.println("大老婆温柔哄睡");
}}
class bWife implements Wife{
@Override
public void sleep() {
System.out.println("小老婆甜美哄睡");
}}
class cWife implements Wife{
@Override
public void sleep() {
System.out.println("美女老婆贴身哄睡");
}}
单例模式
让类的对象只能有唯一的一个实例
懒汉式
- 好处:避免资源浪费(需要对象的时候就创建对象)
- 缺点 :线程不安全
解决:
1、DCL(双重检测锁)
DCL的问题:1、指令重排 2、多线程可见性
解决:volatile关键字修饰
2、使用静态内部类(什么时候使用静态内部类,什么时候就加载)
public class Singleton02 {
private static volatile Singleton02 singleton02; //volatile
private static Object obj = new Object();
private Singleton02(){
}
public static Singleton02 getInstance(){
//双重检验锁 DCL(double check lock) 1、指令重排 2、可见性(在多线程间可见)
if(singleton02 == null){
synchronized (obj){//互斥锁标记
if(singleton02 == null){
//java中允许指令重排序
singleton02 = new Singleton02();
}
}
}
return singleton02;
}
}
饿汉式
- 好处:线程安全。
- 缺点:浪费资源。只要类被加载,那么这个类实例就会被创建
public class Singleton01 {
private static Singleton01 singleton01 = new Singleton01();
private Singleton01(){
}
public static Singleton01 getInstance(){
return singleton01;
}
}
枚举
- 枚举是一个引用类型,枚举是一个规定了取值范围的数据类型。
- 一般已经确定类的对象个数,可以使用枚举定义
- 定义枚举使用enum关键字。
- 枚举中常量是当前类型的静态常量。
- 枚举是一个终止类,并继承Enum抽象类。
- 枚举中必须要包含枚举常量,也可以包含属性、方法、私有构造方法。
- 枚举常量必须在前面,多个常量之间使用逗号隔开
注解
- 注解(Annotation):是代码里的特殊标记, 程序可以读取注解,一般用于替代配置文件。
- 可以通过反射技术去得到类里面的注解,以决定怎么去运行类。
- 定义注解使用@interface关键字,注解中只能包含属性。
- 如果注解中属性是Value时,且只有一个Value属性必填时Value可以省略
- 如果注解中属性有默认值可以不用设置
- 注解中的属性类型可以是基本类型、String类型、注解类型、数组
- 如果注解中的属性为数组类型,且属性值为一个时大括号可以省略
元注解
加在注解上的注解
@Retention:定义注解的使用范围
- Class (默认的) class源文件期间保留
- Source 编译期间保留
- Runtime 在运行期保留
@Target: 定义注解的使用范围
- TYPE, 类上使用
- FIELD, 属性上使用
- METHOD, 方法上使用
- PARAMETER, 参数上使用