1、枚举
1.1枚举简介
JDK1.5引入了新的类型——枚举。
在JDK1.5之前,我们定义常量都是: public static fian1.... 。很难管理。
枚举,可以把相关的常量分组到一个枚举类型里,而且枚举提供了比常量更多的方法。
用于定义有限数量的一组同类常量,例如:
错误级别:
低、中、高、急
一年的四季:
春、夏、秋、冬
商品的类型:
美妆、手机、电脑、男装、女装...
在枚举类型中定义的常量是该枚举类型的实例。
1.2枚举的定义格式
权限修饰符 enum 枚举名称{
实例1,实例2,实例3,实例4;
}
1.3了解:枚举的演化
jdk1.5之前要实现类似枚举的功能:
实现:描述级别(同一种类型的有限个常量)
这时候还没有枚举的类型,所有的功能需要自己实现
首先要创建一个描述级别的类:然后里面设置常量
public class Level {
public static final Level LOW = new Level(1);
public static final Level MEDIUM = new Level(50);
public static final Level HIGH = new Level(100);
private int levelValue;
private Level(int levelValue){
this.levelValue = levelValue;
}
public int getLevelValue() {
return levelValue;
}
public void setLevelValue(int levelValue) {
this.levelValue = levelValue;
}
}
public static void main(String[] args) {
System.out.println(Level.MEDIUM.getLevelValue());
}
通常,还要有许多其它的需求,比如比较枚举值的大小等等…这就需要往里面再添加大量的方法,每当有一个枚举的需求,就需要做大量这样重复的工作…
于是jdk1.5以后就出现了枚举的类型
jdk1.5以后枚举的写法:
public enum Level2 {
LOW(1),MEDIUM(50),HIGH(100);
private int levelValue;
private Level2(int levelValue){
this.levelValue = levelValue;
}
public int getLevelValue() {
return levelValue;
}
public void setLevelValue(int levelValue) {
this.levelValue = levelValue;
}
}
//上述定义方式与之前的功能一样的
//甚至可以这么写
public enum Level3 {//这么简单的定义方式反而更加常用,根据字面描述就已经可看出大小了
LOW,MEDIUM,HIGH;
}
1.4枚举类的常用方法
Enum抽象类常见方法
实例:
public class demo {
public static void main(String[] args) {
System.out.println(Level3.LOW.compareTo(Level3.HIGH));//-2
System.out.println(Level3.LOW.compareTo(Level3.MEDIUM));//-1
System.out.println(Level3.HIGH.compareTo(Level3.LOW));//2
System.out.println(Level2.LOW.compareTo(Level2.HIGH));//-2
System.out.println(Level2.LOW.name());//LOW
System.out.println(Level2.LOW.toString());//LOW
System.out.println(Level2.LOW.ordinal());//0
System.out.println(Level2.MEDIUM.equals(Level2.MEDIUM));//true
//参数1:要返回的枚举类型,参数2:要获取枚举类型中哪个常量对象(提供对象的名字的String)
Level2 x = Enum.valueOf(Level2.class,"HIGH");
System.out.println(x.name());//HIGH
}
//枚举的常用操作(方法),枚举中经常使用switch来进行操作,如下:
public static void haha(Level2 l ){
switch (l){
case LOW:break;
case MEDIUM:break;
case HIGH:break;
}
}
}
1.5实现接口的枚举类
当使用enum创建枚举类时,是默认继承了Enum抽象类的。java中是不允许多继承的,所以使用enum定义的类不能继承其它类,只能通过实现接口。、
实例:
//定义一个接口
interface LShow{
void show();
}
//
public enum Level3 implements LShow{
LOW,MEDIUM,HIGH;
@Override
public void show() {
System.out.println("级别对象在调用show方法,该对象的级别为:"+this.name());
}
}
//main方法
public static void main(String[] args) {
Level3.LOW.show();//级别对象在调用show方法,该对象的级别为:LOW
}
虽然可以这样操作,但是每个枚举都是一个独立的对象,按照java的逻辑,应该是对象调用不同方法,而不是多个对象共享同一个方法。于是 枚举中:可以 为每个枚举对象 添加自己独特的 对于接口方法的实现:
public enum Level3 implements LShow{
LOW(){
@Override
public void show() {
System.out.println("低等级在调用show方法");
}
},MEDIUM(){
@Override
public void show() {
System.out.println("中等级在调用show方法");
}
},HIGH(){
@Override
public void show() {
System.out.println("高等级在调用show方法");
}
}
}
1.6枚举的注意事项
- 一旦定义了枚举,最好不要妄图修改里面的值,除非修改是必要的。
- 枚举类默认继承的是java.lang.Enum类而不是Object类
- 枚举类不能有子类,因为其枚举类默认被final修饰
- 只能有private构造方法
- switch中使用枚举时,直接使用常量名,不用携带类名
- 不能定义name属性,因为自带name属性
- 不要为枚举类中的属性提供set方法,不符合枚举最初设计初衷。
2、注解
2.1注解简介
Java注解(Annotation) 又称Java标注,JDK5.0引入的一注释机制。
Java语言中的类、方法、变量、参数和包等都可以被标注。和注释不同,Java标注可以通过反射获取标注内容。在编译器生成类文件时,标注可以被嵌入到字节码中。Java 虚拟机可以保留标注内容,在运行时可以获取到标注内容。当然它也支持自定义Java标注。
理解:相当于一种可以被编译进class文件的注释,注释是给人看的,注解是给机器看的。
- 主要用于
- 编译格式检查
- 反射中解析
- 生成帮助文档
- 跟踪代码依赖
- 等
2.2学习的重点
理解Annotation的关键是理解其语法和用法。
学习步骤:
- 概念
- 怎么使用内置注解
- 怎么自定义注解
- 反射中怎么获取注解内容
2.3内置注解
-
@Override : 重写 *
-
定义在java.lang.Override
-
作用:编译格式检查注解,当方法的注解是@Override,该方法必须是重写了父类的方法。
-
-
@Deprecated:废弃 *
- 定义在java.lang,Deprecated
-
@SafeVarags
- Java 7 开始支持,忽略任何使用参数为泛型变量的方法或构造函数调用产生的警告。
-
@FunctionalInterface:函数式接口 *
- Java 8开始支持,标识一个匿名函数或函数式接口(比如Runnable)
-
@Repeatable:标识某注解可以在同一声明上使用多次
- Java 8开始支持,标识某注解可以在同一声明上使用多次
-
@SuppressWarnings:抑制编译时的警告信息
-
定义在java.lang.SuppressWarnings
-
三种使用方式
1.@SuppressWarnings("unchecked")[^抑制单类型的警告] 2.@SuppressWarnings("unchecked","rawtypes")[^抑制多类型的警告] 3.@SuppressWarnings("all")[^抑制所有类型的警告]
-
参数列表:
关键字 用途 all 抑制所有警告 boxing 抑制装箱、拆箱操作时候的警告 cast 抑制映射相关的警告 dep-ann 抑制启用注释的警告 deprecation 抑制过期方法警告 fallthrough 抑制确在switch中缺失breaks的警告 finally 抑制finally模块没有返回的警告 hiding 抑制相对于隐藏变量的局部变量的警告 incomplete- switch 忽略没有完整的switch语句 nls 忽略非nls格式的字符 null 忽略对nul的操作 rawtypes 使用generics时忽略没有指定相应的类型 restriction 抑制禁止使用劝阻或禁止引用的警告 serial 忽略在serializable类中没有声明serialVersionUID变量 static-access 抑制不正确的静态访问方式警告 synthetic-access 抑制子类没有按最优方法访问内部类的警告 unchecked 抑制没有进行类型检查操作的警告 unqualified-field-access 抑制没有权限访问的域的警告 unused 抑制没被使用过的代码的警告 -
2.4元注解
1、简介
作用在其它注解的注解
2、有哪些
-
@Retention - 标识这个注解怎么保存(持久化方案):
- 是只在代码中
- 编译入class文件
- 还是在运行时可以通过反射访问
-
@Documented - 标记这些注解是否包含在用户文档中。
-
@Target - 标记这个注解应该是那种Java成员(类/方法/一句代码/等)
-
@Inherited - 标记这个注解是自动继承的
-
1. 子类会继承父类使用的注解中被@Inherited修饰的注解 2. 接口继承关系中,子接口不会继承父接口中的任何注解,不管父接口中使用的注解有没有被@Inherited修饰 3. 类实现接口时不会继承任何接口中定义的注解
-
2.5自定义注解
1.注解架构
Annotation与RetentionPolicy与ElementType
每一个Annotation对象,都会有唯一的RetentioPolicy属性;至于ElementType属性,则有1-n个。
ElementType(注解的用途类型)
“每一个Annotation”都与“1-n个ElementType”关联。当Annotation与某个ElementType关联时,就意味着:Annotation有了某种用途。
例如:若一个Annotation对象是METHOD类型,则该Annotation只能用来修饰方法。
package java.lang.annotation;
public enum ElementType {
TYPE,//类、接口(包括注释类型)或枚举声明
FIELD,//字段声明(包括枚举常量)
METHOD,//方法声明
PARAMETER,//参数声明
CONSTRUCTOR,//构造方法声明
LOCAL_VARIABLE,//局部变量声明
ANNOTATION_TYPE,//注释类型声明
PACKAGE,//包声明
TYPE_PARAMETER,
TYPE_USE,
MODULE
}
RententionPolicy(注解作用域策略)
“每一个Annotation”都与“一个RententionPolicy”关联
若Annotation的类型为:
- SOURCE:则意味着,Annotation仅存在于编译器处理期间,编译器处理完之后就没用了。
例如: “@Override”标志就是一个Annotation。当它修饰一个方法的时候,就意味着该方法覆盖父类的方法;并且编译期间会进行语法检查!编译器处理完后,“@Override”就没有任何作用了。
-
CLASS:则意味着,编译器将Annotation存储于类对应的.class文件中,它是Annotation的默认行为。
-
RUNTIME:则意味着,编译器将Annotation存储与class文件中,并且可由JVM读入。
public enum RetentionPolicy {
SOURCE,
CLASS,
RUNTIME
}
2.定义格式
@interface 自定义注解名{}
3.注意事项
1.定义的注解,自动实现了java.lang annotation.Annotation接口
2.注解中的每一一个方法,实际是声明的注解配置参数
- 方法的名称就是配置参数的名称
- 方法的返回值类型,就是配置参数的类型。只能是:基本类型/Class/String/enum
3.可以通过default来声明参数的默认值
4.如果只有一个参数成员,一般参数名为value(传参时缺省参数名,默认为value,前提是只有一个参数)
5.注解元素必须要有值,我们定义注解元素时,经常使用空字符串、0作为默认值。
4.案例
@Retention(RetentionPolicy.CLASS)//持久化方案:
@Documented()//有此注解,表示包含在用户文档
@Target({ElementType.TYPE,ElementType.METHOD})//作用对象(或范围)
@Inherited//有此注解,表示自动继承
public @interface MYAnnotation {
//参数:
// 格式:参数类型 参数名() default 默认值;
String value() default "";//参数名传入时缺省默认为value。
}
@interface
使用@interface定义注解时,意味着它实现了java.lang.annotation.Annotation 接口,即该注解就是一个
Annotation。
定义Annotation时,@interface是必须的。
注意:它和我们通常的implemented实现接口的方法不同。Annotation 接口的实现细节都由编译器完成。通过@interface定义注解后,该注解不能继承其他的注解或接口。
@Documented
类和方法的Annotation在缺省情况下是不出现在javadoc中的。如果使用@Documented修饰该Annotation,
则表示它可以出现在javadoc中。
定义Annotation时,@Documented可有可无;若没有定义,则Annotation不会出现在javadoc中。
@Target(ElementType.TYPE)
前面我们说过,ElementType是Annotation的类型属性。而@Target的作用,就是来指定Annotation的类型属性。
@Target(ElementType.TYPE)的意思就是指定该Annotation的类型是ElementType.TYPE.这就意味着,MyAnnotation是来修饰"类、接口(包括注释类型)或枚举声明”的注解。
定义Annotation时,@Target可有可无,若有@Target,则该Annotation只能用于它所指定的地方;若没有@Target,则该Annotation可以用于任何地方。
@Retention(RetentionPolicy.RUNTIME)
前面我们说过,RetentionPolicy是Annotation的策略属性,而@Retention的作用,就是指定Annotation的策略属性。
@Retention(RetentionPolicy.RUNTIME)的意思就是指定该Annotation的策略是RetentionPollcy.RUNTIME。这就意味着,编译嚣会将该Annotation信息保留在.class文件中,并且能被虚拟机读取。
定义Annotation时,@Retention可有可无。若没有@Retention,则默认是RetentionPolicy.CLASS.
3、反射
1、概述
JAVA反射机制是在运行状态中:
获取任意一个类的结构,
创建对象
得到方法
执行方法、调用属性
这种在运行状态动态获取信息以及动态调用对象方法的功能被称为java语言的反射机制。
使用场景/需求:
场景,已知程序开发中必定要创建一个Person类来存储对象,但是开发计划中是在半个月后创建Person,但是现在我们需要使用Person类的对象、方法、属性,先完成业务逻辑的编码。但是我们现在不能直接使用Person p = new Person()来创建对象,因为Person类还没有创建。
虽然Person还没创建,但是我们已经知道Person存储的包、属性和方法。于是可以使用反射机制,来操作Person类。
2、类加载器
Java类加载器(Java Classloader)是Java运行时环境(Java Runtime Environment)的一部分,负责动态加载Java类到Java虚拟机的内存空间中。
java默认有三种类加载器,BootstrapClassLoader、ExtensionClassLoader、AppClassLoader。
BootstrapClassLoader(引导启动类加载器):
嵌在JVM内核中的加戟器,该加献器是用C++语言写的(无法用Java代码直接使用),主要负载加载JAVA_HOME/1ib下的类库,引导启动类加载器无法被应用程序直接使用。
ExtensionClassLoader(扩展类加载器):
ExtensionClassLoader是用JAVA编写,且它的父类加载器是Bootstrap。
是由sun.misc.Launcher$ExtClassLoader实现的,主要加载JAVA_HOME/lib/ext目录中的类库。
它的父加载器是BootstrapClassLoader
AppClassLoader(应用类加载器):
AppClassLoader是应用程序类加载器,负责加载应用程序classpath目录下的所有jar和class文件。它的父加载
器为ExtClassLoader
类通常是按需加载,即第一次使用该类时才加载。由于有了类记载其,Java运行时系统不需要知道文件与文件系统。学习类加载器时,掌握Java的委派概念很重要。
双亲委派模型:如果一个类加载器收到了一个加载请求,它不会自己去尝试加载这个类,而是把这个请求专拣给父类加载器去完成。因为所有的类加载请求都应该传递到最顶层的启动类加载器中,只有到父类加载器反馈自己无法完成这个加载请求(在它得分搜索范围内没有找到这个类)时,子类加载器才会尝试自己去加载。委派的好处就是避免有些类被重复加载。
- 实例:
public class ClassLoaderDemo {
/**
* 类加载器demo
* @param args
*/
public static void main(String[] args) throws IOException {
//使用类加载器去加载配置文件
//获取类加载器的方式:某个类名.class.getClassLoader()就能在内存中获取到这个类的类加载器
System.out.println(ClassLoaderDemo.class.getClassLoader());//测试输出:jdk.internal.loader.ClassLoaders$AppClassLoader@1f89ab83
//获取一个在资源根目录(相对路径)下的(如果没有资源根目录,就获取src下的)文件的输入流
InputStream is = ClassLoaderDemo.class.getClassLoader().getResourceAsStream("./com/zx/fanshe/demo1.txt");
BufferedReader bf = new BufferedReader(new InputStreamReader(is));
String text = bf.readLine();
System.out.println(text);
bf.close();
}
}
3、所有类型的Class对象
当定义一个Person类时,程序运行时Person类会加载到内存中:
Person = new Person();
这时候在内存中p对象指向的是一个地址,这块内存地址存储的是一个Person类型的数据,这些数据也就是p对象的内容。
上面就是Person的对象在内存中的存储方式,是以Person类型对象存储的;
那么,Person类在内存中是如何存储的呢?
答:也是以对象的形式存储的,这个对象是的类型是Class。调用Person.class,就可以得到这个class对象,java中所有的类都是以Class类的一个对象。
总结:
Person是一个类型,其对象是Person类型的对象,存储 Person 类型的数据
Class也是一个类型,其对象是Class类型的对象,存储 类 类型的数据
要想了解一个类,必须先获取到该类的字节码文件对象。
在Java中,每一个字节码文件,被加载到内存后,都会存在其一个对应的Class类型的对象
4、得到Class的几种方式
1. 如果拥有类的对象,可以通过
Class 对象.getClass() 得到一个类的 类对象
2. 如果在编写代码时,知道类的名称,可以通过
Class.forName(包名+类名):得到一个类的 类对象
3. 如果在编写代码时,知道类的名称,且类已经存在,可以通过
包名.类名.class 得到一个类的 类对象
上述三种方式,在调用时,如果类在内存中不存在,则会加载到内存!如果类已经在内存中存在,不会重复加载,而是重复利用!
(一个class文件 在内存中不会存在两个类对象)
特殊的类对象:
基本数据类型的类对象:
基本数据类型.class
包装类.type
基本数据类型包装类对象:
包装类.class
//实例:
//1. 如果拥有类的对象,可以通过: Class c = 对象.getClass() 得到一个类的 类对象
Person p = new Person("0001", "张三", 18);
Class class1 = p.getClass();
System.out.println(class1);
//2. 如果在编写代码时,知道类的名称,可以通过: Class.forName(包名+类名):得到一个类的 类对象
Class Class2 = Class.forName("com.zx.Person");//这种方式是可以在Person对象并不存在的时候去使用的
System.out.println(Class2);
//3. 如果在编写代码时,知道类的名称,且类已经存在,可以通过: 包名.类名.class 得到一个类的 类对象
Class<Person> class3 = com.zx.Person.class;
System.out.println(class3);
System.out.println(class1==class3 &&class1==class2);//true
5、获取Constructor(构造方法)
通过class对象 获取一个类的构造方法
1. 通过指定的参数类型,获取指定的单个构造方法
getConstructor(参数类型的class对象数组);
2. 获取构造方法数组
getConstructors();
3. 获取所有权限的单个构造方法
getDeclaredConstructor(参数类型的class对象数组);
4. 获取所有权限的构造方法数组
getDeclaredConstructors();
实例1:
//1.通过指定的参数类型,获取指定的单个构造方法:getConstructor(参数类型的class对象数组)
//Person中实现了一个一参的private构造方法,由于private限制,这里需要获取所有权限getDeclaredConstructor,并且忽略权限检查setAccessible。
Class<Person> aClass1 = (Class<Person>) Class.forName("com.zx.Person");
Constructor<Person> c1 = aClass1.getDeclaredConstructor(String.class);
//忽略权限的检查
c1.setAccessible(true);
Person p = c1.newInstance("0001");
System.out.println(p);
实例2:上面的代码可以修改为,这段代码可以在Person类不存在的情况下使用
//获取类对象
Class aClass1 = Class.forName("com.zx.Person");
//获取一个构造方法
Constructor c1 = aClass1.getConstructor();
//构造一个对象
Object o = c1.newInstance();
System.out.println(o);
Constructor—创建对象
Constructor的常用方法就是上面实例中的:
1. newInstance(Object... pata)
调用这个构造方法,把对应的对象创建出来
参数:是一个Object类型的可变参数,传递的参数顺序必须匹配构造方法中形式参数列表的顺序!
2. setAccessible(boolean flag)
如果flag为true 则表示忽略访问权限检查!(可以访问任何权限的方法)
6、获取Method(方法)
通过class对象获取一个类的方法
1. getMethod(string methodName,class.. clss)
根据参数列表的类型和方法名,得到一个方法(public修饰的)
2. getMethods();
得到一个类的所有方法(public修饰的)
3. getDeclaredMethod(string methodName,class.. clss)
根据参数列表的类型和方法名,得到一个方法(除继承以外所有的:包含私有,共有,保护,默认)
4. getDeclaredMethods() ;
得到一个类的所有方法(除继承人外所有的:包含私有,共有,保护,默认)
Method执行方法
invoke(Object o,0bject... para) :
调用方法
参數1.要调用方法的对象
参数2.要传递的参数列表
getName()
获取方法的方法名称
setAccessible(boolean flag)
如果flag为true则表示忽略访问权限检查 ! (可以访问任何权限的方法)
实例:
//获取类对象
Class aClass1 = Class.forName("com.zx.Person");
//获取一个构造方法
Constructor c1 = aClass1.getConstructor();
//构造一个对象
Object o = c1.newInstance();
//使用类对象获取方法:getDeclaredMethod——根据参数列表类型和方法名
Method method = aClass1.getDeclaredMethod("PrivateMethod");
//忽略权限检查
method.setAccessible(true);
method.invoke(o);
7、获取Field
通过class对象获取一个类的属性
1. getDeclaredField(String filedName)
根据属性的名称,获取一个属性对象(所有属性)
2. getDeclaredFields ()
获取所有属性
3. getField(String filedName)
根据属性的名称,获取一个属性对象(public属性)
4. getFields()
获取所有属性(public)
Field属性的对象类型
常用方法:
1. get(object o);
参数:要获取属性的对象
获取指定对象的此属性值
2.set(object o,object value);
参数1.要设置属性值的对象
参数2.要设置的值
设置指定对象的属性的值
3. getName()
获取属性的名称
4. setAccessible(boolean flag)
如果flag为true则表示忽略访问权限检查 ! (可以访问任何权限的属性)
实例:
//获取类对象
Class aClass1 = Class.forName("com.zx.Person");
//获取一个构造方法
Constructor c1 = aClass1.getConstructor();
//构造一个对象
Object o = c1.newInstance();
//使用类对象获取属性:getDeclaredField——根据属性名获取所有权限的属性
Field field = aClass1.getDeclaredField("name");
//忽略权限检查
field.setAccessible(true);
//1.get()方法:获取指定对象的此属性值,o:要获取该属性的对象
System.out.println(field.get(o));
//2、set()方法:设置指定对象的属性值,参数1:要设置属性的对象;参数2:要设置的值
field.set(o,"张三");
System.out.println(field.get(o));
//3、getName()方法:获取属性的名称
System.out.println(field.getName());
8、获取注解信息
后续学习框架的原理就是:
通过反射的,获取到某个类,扫描类的注解、扫描类的属性的注解,获取到注解传入的参数值,从而对这个类的对象进行更好的处理。好处就是,不需要再对该类的每个对象进行相同的处理。
获取类/属性/方法的全部注解对象
Annotation [] as = (Class/Field/Method类型的)对象.getAnnotations();
for(Annotation a : as){
System.out.println(a);
}
根据类型获取类/属性/方法的注解对象
注解类型 对象名 = (注解类型) c.getAnnotation(注解类型.class);
实例
//1.定义两个注解
//注解1:这是一个作用在类上的,映射到数据库 表 的注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
public @interface TableAnnotation {
String value();
}
//注解2:这是一个作用在属性上,映射到数据库 字段属性 的注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@Documented
public @interface ColunmAnnotation {
String column_name();
String type();
String length();
}
//2.定义一个Book实体类,并添加注解,将这个实体类的各种属性映射到数据库
@TableAnnotation("Test_Book")
public class Book {
@ColunmAnnotation(column_name = "id", type = "varchar", length = "20")
private String id;
@ColunmAnnotation(column_name = "name", type = "varchar", length = "36")
private String name;
@ColunmAnnotation(column_name = "info", type = "varchar", length = "36")
private String info;
public Book(String id, String name, String info) {
this.id = id;
this.name = name;
this.info = info;
}
@Override
public String toString() {
return "Book{" +
"id='" + id + '\'' +
", name='" + name + '\'' +
", info='" + info + '\'' +
'}';
}
}
//3.main方法:
// (1)获取Book类的class对象。
// (2)通过class对象,获取其:class类上的注解、属性上的注解。
// (3)通过注解的参数值,获取到该类的【类本身、属性】与数据库的映射关系
public class Demo5_GetAnnotation {
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException {
//获取class对象
Class aClass = Class.forName("com.zx.fanshe.Book");
//获取class类的注解
TableAnnotation ta = (TableAnnotation) aClass.getDeclaredAnnotation(TableAnnotation.class);
String value = ta.value();
System.out.println("类名:"+aClass.getSimpleName()+"; 数据库中的表名:"+value);
//根据class对象获取其属性
Field[] fields = aClass.getDeclaredFields();
for(Field f:fields){
//获取属性的注解
ColunmAnnotation ca = f.getAnnotation(ColunmAnnotation.class);
String column_name = ca.column_name();
String length = ca.length();
String type = ca.type();
System.out.println(f.getName()+"属性:\n 对应数据库中的字段:"+column_name+"; 数据类型:"+type+"; 长度:"+length);
}
}
}
//输出:
/*
类名:Book; 数据库中的表名:Test_Book
id属性:
对应数据库中的字段:id; 数据类型:varchar; 长度:20
name属性:
对应数据库中的字段:name; 数据类型:varchar; 长度:36
info属性:
对应数据库中的字段:info; 数据类型:varchar; 长度:36
*/
4、内省
简介
基于反射 , java所提供一套应用到JavaBean的API
一个定义在包中的类 ,
拥有无参构造器
所有属性私有
所有属性提供get/set方法
实现了序列化接口
这种类,我们称其为 bean类.
Java提供了一套java.beans包的api , 对于反射的操作们进行了封装!
Introspector
获取Bean类信息
方法:
BeanInfo getBeanInfo(Class cls)
通过传入的类信息,得到这个Bean类的封装对象.
BeanInfo
常用的方法:
MethodDescriptor [] getPropertyDescriptors():
获取bean类的get/set方法 数组
MethodDescriptor
常用方法:
1. Method getReadMethodO;
获取一个get方法
2. Method getWr iteMethodO;
获收一个set方法
实例
//1.创建一个Bean类Express
//属性:
public class Express implements Serializable {
private String id;
private String name;
private boolean flag;
}
//2.main方法
public static void main(String[] args) throws Exception {
Class aClass = Class.forName("com.zx.neixing.Express");
//传入类信息,得到i这个Bean类的封装对象
BeanInfo beanInfo = Introspector.getBeanInfo(aClass);
//获取BeanInfo对象每个属性的的get/set方法数组,数组中每一个数据存储一个属性的get和set方法
PropertyDescriptor[] pds = beanInfo.getPropertyDescriptors();
//遍历数组,获取get/set方法
for(PropertyDescriptor pd:pds){
System.out.println("属性名:"+pd.getName());
System.out.println("类型:"+ pd.getPropertyType());
Method get = pd.getReadMethod();
Method set = pd.getWriteMethod();
System.out.println("该属性的get方法:"+get);
if("class".equals(pd.getName())){
System.out.println("class只有getclass()方法,没有set方法");
}
if("boolean".equals(pd.getPropertyType().getName())){
System.out.println("boolean类型的get方法为:is属性名()而不是get属性名()");
}
System.out.println("该属性的set方法:"+set);
System.out.println();
System.out.println();
}
}
内省总结
内省是java提供的基于反射、用于操作bean类的API,提供了大量的操作方法。
比如上面的例子:相比于反射,使用内省做到了更快速的获取get/set方法