Day12=枚举+注解+反射+类加载器+双亲委派+如何加载配置文件+class对象+反射获取注解+内省

枚举

(记忆中可以阻止反射破坏单例模式?)
定义多个常量(public static final)并分组管理。
举例:Thread.state,有六种状态,每个都是该类对象

枚举定义

public enum Level{
	LOW(1),MID(50),HIGH(100);//描述完毕
	private int levelVal;
	private Level(int levelVal){
		this.levelval = levelVal;
	}
	
}

或者:

public enum Level{
	LOW,MID,HIGH;
}

Enum是个抽象类

只有一个toString()可以重写
获取对象Level x = Enum.valueOf(Level.class,"LOW");
Level.Low.show();

定义接口,实现不同的show

public enumm Level implements LShow{
	LOW(){
		@Override
		public void show(){
			System.out.println("低级别");
		}
	},MID{ //这里()可写可不写,调用午餐构造方法
		@Override
		public void show(){
			System.out.println("中级别");
	}
}

interface LShow{
	void show();
}

枚举类使用时注意事项

  • 定义好之后尽量不修改
  • 默认继承的是java.lang.Enum而不是Object
  • 枚举类不能有子类,默认被final
  • 只能有private构造方法,不允许外部创建他
  • switch中使用时直接使用常量名,不带类名
  • 不要提供set属性的方法
  • 不能定义name属性,因为它自带name

注解

Annotation,JDK5.0引入的注释机制
可以标注的:类、方法、变量、参数、包。

注释是不会编译到class文件里的,注解是给机器看的,可以被嵌入到字节码中。

注解有什么作用?

  • 编译格式检查
  • 反射中解析(通过反射获取内容)
  • 生成帮助文档
  • 跟踪代码依赖
  • 。。。其他

内置注解

  • @Override 重写 【编译格式检查,必须重写了父类的方法】
  • @Deprecated 废弃 【不用了,开发时会利用反射发现这个方法废弃并告知】
  • @SafeVarargs 忽略任何使用参数为泛型变量的方法或构造函数调用产生的警告 【JDK7出现】
  • @FunctionalInterface 函数式接口 【8开始,标识一个匿名函数或函数式接口】

只包含一个方法的接口 lambda无法单独出现,需要一个函数式接口来盛放,lambda表达式方法体就是函数接口的实现。Runnable r = ()->System.out.println("lambda");

  • @SuppressWarnings 抑制编译时的警告信息(“all”)
    获取方法->获取方法注解

元注解与自定义注解

元注解是给自定义注解加注解,进行一些配置。

  • @Retentino 保持,注解应该只在代码中还是编入class中或者运行时反射访问(枚举)
  • @Documented 这些注解是否包含在用户文档javadoc
  • @Target 标记这个注解是那种Java成员
  • @Inherited 注解是自动继承的 子类会自动继承父类使用的注解中被@Inherited修饰的注解,接口继承中不会接收任何父接口中的注解,类实现接口时也不会
    自定义注解关系:
  • 指定数个ElementType确定范围(方法,参数,字段,类型)(这个也是枚举)
  • RetentionPolicy 属性唯一 持久策略

定义格式

@interface name()

@Documented
@Target({ElementType.TYPE, ElementType.METHOD})//可以用在类或方法上,控制注解可以作用的位置
@Retention(RetentionPolicy.RUNTIME)//一个注解至少对应一个持久策略(Runtime包含class包含source)
@Inherited //可以继承
@interface MyAnnotation{ //自动继承java.lang.annotation.Annotation接口
	String value() default "aa";//给一个默认值
	int num() default 1;//给一个默认值
}

@MyAnnotation(value="xx",num=100)
public class Demo{
}

反射(国企特别喜欢考这点)

运行状态中获取任意一个类的结构去创建对象,去得到方法,执行方法和属性操作。正常的流程是通过java文件编写代码转换为class文件再由类加载器加载到内存,jvm通过内存里的类信息创建对象。反射是在运行状态获取信息并动态调用对象方法。

  • 反射reflection机制,在程序的运行状态中,构造任意类的对象, 了解任意对象所属的类,了解任意类的成员变量和方法,调用任意对象属性和方法。(反封装)
  • 体现在动态(代码运行过程中)获取程序信息和动态调用对象功能。

类加载器

是Java运行时环境的一部分,负责动态加载类到JVM的内存空间里。
默认有三种类加载器:

  • 引导启动类加载器 BootstrapClassLoader 用C++写的,加载JAVA_HOME/lib下的类库⬇️
  • 扩展类加载器 ExtensionClassLoader⬇️
  • 应用类AppClassLoader 负责加载应用程序classpath目录下的所有jar和class文件
    父->子->子的子这个关系

双亲委派模型(面试常考)

当子加载类时,首先会告知父加载这个类,父又往上找父,如果Bootstrap没有加载(搜索范围内没找到这个类),那么让子加载。这样可以去避免有些类被重复加载。
如何加载配置文件?找到app加载器(通过Demo1.class.getClassLoader().getResourceAsStream(“config.txt”);这样可以直接获取输入流之后再打印)。
如果修改文件夹为source,再getResourceAsStream就不是src下的了,就时source文件夹里的那个文件。

所有类型的class对象

Demo.java Person.java–>>编译–>>Demo.class Person.class–>>加载–>>内存(Class类型的对象Demo.class和Person.class)

得到Class的三种方式(面试常考)

  1. 拥有类的对象,可以通过 .getClass()得到类对象
  2. 知道类的名称,Class.forName(包名+类名)
  3. 知道类的名称且类已经存在,直接包名+类名.class就可以得到一个类的类对象
    调用时,如果类不在内存中,则会加载到内存。如果已经存在,不会重复加载,直接用。(一个class文件在内存中不会存在两个类对象)
    举例:
//1. 包.类.class
Class<Person> c1 = com.java.demo.Person.class;
//2. 已有类对象
Class<Person> c2 = (Class<Person>)p.getClass();//需要强转
//通过==比较c1c2是true
//3. Person都不存在,让他自己找包
Class.forName("com.java.demo.Person");//注意抛出ClassNotFoundException

如果把person删了编译时3是不会报错的。其他都不行。只有在运行时才知道不行。

通过反射获取Constructor构造方法

  1. getConstructor(参数类型的class) 指定的参数类型来获取指定的构造方法【获取对象的类->获取对象的构造方法->指定新的Class对象数组,里面包含指定的参数的.Class】
Constructor c = p.getClass().getConstructor(new Class[]{String.class, int.class});
  1. 获取构造方法数组 getConstructors();
    举例:
//把Person的类加载到内存
Class<Person> pClass = (Class<Person>) Class.forName("com.java.demo.Person");
//找到全参构造方法
Constructor<Person> p1 = pClass.getConstructor(String.class, int.class);
//或者new Class[]{String.class, int.class}
//使用构造方法创建对象
Person p = p1.newInstance();

如何忽略构造方法的private?getDeclaredConstructor()+p1.setAccessible(true);这样就可以获取访问受限的构造方法【打破单例模式】
总结:创建对象

  • 如果为true则表明忽略访问权限检查setAccessible(true);
  • newInstance()调用构造方法把对象创建出来

通过反射获取方法

  1. getMethod(mathodName, class)
  2. getMethods
  3. getDeclaredMethod(String methodNam, class…class)
  4. getDeclaredMethods
  • 执行方法:method.invoke(对象,传参);
//加载类
Class c1 = Class.forName("com.jav.demo.Person");//泛型可以不指定,但创建对象时要强转
//获取构造方法
Constructor c = c1.getConstructor();
//创建对象
Object o = c.newInstance();
//获取类的方法
c1.getMethod("setName", param:String.class);
//执行方法 执行setName方法的对象;调用方法时传递的参数0-n个
setName.invoke(o,"xx");

通过反射获取Field属性

  1. getDeclaredField(String fieldName);根据属性名称获取属性对象
  2. getDeclaredFields()获取所有属性
  3. getField(String fieldName)根据属性名称获取属性对象(public)
  4. getFields()获取所有属性public
    操作
  • f.get(Object o);参数是要获取属性的对象,获取指定对象的该属性值
  • f.set(Object o, Object value);对象,要设置的值
  • getName()获取属性的名称
  • setAccessible(flag)
    举例
//...创建对象o,类是c
Field phone = c.getField("phone");
phone.set(o,"123");

通过反射获取注解

ORM框架 对象关系映射

Person类->数据库里创建Person表格里面是一行各种属性

创建注解
//类与表名对应
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface TableAnnotation{
	//用于标注某个类对应的表格名称
	String value();
}

//属性与列对应(名称、类型、长度)
@Target(ElementType.FIELD)//对应属性
@Retention(RetentionPolicy.RUNTIME)
public @interface ColumnAnnotation{
	//描述列名
	String colName();
	//描述类型
	String type();
	//描述数据长度
	String length();
}

public class Book {
//Book类对应数据库中的Book表
	@ColumnAnnotation(columnName = "id", type="int", length = "11")
	private int id;
	@...
	private String name;
	@...
	private String info;
}

RetentionPolicy持久策略,SOURCE注解的信息只记录在源文件中,编译时会丢弃;CLASS注解记录在文件中,但不会加载到JVM中,这也是默认值;RUNTIME注解信息保留在源文件、类文件中,执行时也加载到Java的JVM中,因此可以用反射读取。

//类信息
Class c = Class.forName("com.java.demo2.Book");
//注解
Annotation[] as = c.getAnnotations();
for(Annotation a:as){
	//输出注解
}
TableAnnotation ta = (TableAnnotation)c.getAnnotation(TableAnnotation.class);
String value = ta.value();
Field[] fs = c.getDeclaredFields();
//获取属性注解
for(Field f: fs){
	ColumnAnnotation ca = f.getAnnotation(ColumnAnnotation.class);
//f.getName() ca.columnName() ca.type() ca.length()
}

内省Introspector(基于反射延伸出来的API)应用到JavaBean

bean类(没有包含业务逻辑,存储属性并提供get/set)

重要,理解后设计bean的时候一定要规范,让框架得以运用

  • 无参构造器
  • 所有属性私有
  • 所有属性提供get/set方法
  • 实现序列化接口
    Java提供了一套API对反射的操作进行封装
    getBeanInfo(Class c)传class->得到BeanInfo对象->getPropertyDescriptors()->获得MethodDecriptor[]对象(一个属性的get/set方法)->
  • getReadMethod() get
  • getWriterMethod() set
    通过内省的形式更快地获取bean的get/set,封装好的。
BeanInfo bi = Introspector.getBeanInfo(c);
PropertyDescriptor[] pds = bi.getPropertyDescriptors();
//遍历数组获取属性的get和set方法
for(PropertyDescriptor pd:pds){
	Method get = pd.getReadMethod();
	Method set = pd.getWriteMethod();
	//属性名称 pd.getName();
	//属性类型 pd.getPropertyType();
}

如果属性是boolean的话,get变为isName(),框架也是这么识别的

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
SQLAlchemy 是一个 SQL 工具包和对象关系映射(ORM)库,用于 Python 编程语言。它提供了一个高级的 SQL 工具和对象关系映射工具,允许开发者以 Python 类和对象的形式操作数据库,而无需编写大量的 SQL 语句。SQLAlchemy 建立在 DBAPI 之上,支持多种数据库后端,如 SQLite, MySQL, PostgreSQL 等。 SQLAlchemy 的核心功能: 对象关系映射(ORM): SQLAlchemy 允许开发者使用 Python 类来表示数据库表,使用类的实例表示表中的行。 开发者可以定义类之间的关系(如一对多、多对多),SQLAlchemy 会自动处理这些关系在数据库中的映射。 通过 ORM,开发者可以像操作 Python 对象一样操作数据库,这大大简化了数据库操作的复杂性。 表达式语言: SQLAlchemy 提供了一个丰富的 SQL 表达式语言,允许开发者以 Python 表达式的方式编写复杂的 SQL 查询。 表达式语言提供了对 SQL 语句的灵活控制,同时保持了代码的可读性和可维护性。 数据库引擎和连接池: SQLAlchemy 支持多种数据库后端,并且为每种后端提供了对应的数据库引擎。 它还提供了连接池管理功能,以优化数据库连接的创建、使用和释放。 会话管理: SQLAlchemy 使用会话(Session)来管理对象的持久化状态。 会话提供了一个工作单元(unit of work)和身份映射(identity map)的概念,使得对象的状态管理和查询更加高效。 事件系统: SQLAlchemy 提供了一个事件系统,允许开发者在 ORM 的各个生命周期阶段插入自定义的钩子函数。 这使得开发者可以在对象加载、修改、删除等操作时执行额外的逻辑。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值