用于定义有限数量的一组同类常量,例如: 错误级别: 低级、中级、高级 一年四季:春、夏、秋、冬 商品类别:美妆、手机、数码、护肤、家电... 在枚举类型中定义的常量(如春、高级等)是该枚举类型的实例2、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;
}
}
3、枚举定义
权限修饰符 enum 枚举名称 {
实例1,实例2,实例3,实例4;
}
使用枚举类型定义一个等级类型
public enum DemoLevel02 {
//指定等级对应的水平值
LOW(1),MEDIUM(50),HIGH(100);
//水平值
private int levelValue;
//将构造方法私有化,表示除此类之外其他方法无法调用 -- 保证等级仅由程序员设定
private DemoLevel02(int levelValue){
this.levelValue = levelValue;
}
public int getLevelValue() {
return levelValue;
}
//一般不为枚举对象设置set方法,除非修是必要的,否则不修改枚举的值
public void setLevelValue(int levelValue) {
this.levelValue = levelValue;
}
}
4、枚举常用方法
5、枚举接口 – 实现接口的枚举类
所有的枚举都继承自java.lang.Enum类 由于Java不支持多继承,所以枚举对象不能再继承其他类 每个枚举对象都可以实现自己的抽象方法(接口中定义的抽象方法)
Level.java
interface LShow{
void show();
}
public enum Level03 implements LShow{
LOW{
@Override
public void show(){
System.out.println("低等级");
}
},MEDIUM{
@Override
public void show(){
System.out.println("中等级");
}
},HIGH{
@Override
public void show(){
System.out.println("高等级");
}
};
DemoLevel03.java
public class DemoLevel03 {
public static void main(String[] args) {
System.out.println(Level03.LOW.compareTo( Level03.HIGH )); //-2
System.out.println(Level03.HIGH.compareTo( Level03.LOW )); //2
System.out.println(Level03.LOW.compareTo( Level03.MEDIUM )); //-1
System.out.println(Level03.MEDIUM.compareTo( Level03.LOW )); //1
System.out.println("equals方法:" + Level03.LOW.equals( Level03.HIGH)); //false
System.out.println("equals方法:" + Level03.LOW.equals( Level.LOW )); //false
System.out.println("getDeclaringClass方法:" + Level03.LOW); //LOW
System.out.println("name方法:" + Level03.LOW.name()); //LOW
System.out.println("toString方法:" + Level03.LOW.toString()); //LOW
System.out.println("ordinal方法:" + Level03.LOW.ordinal()); //0
Level03 high = Enum.valueOf( Level03.class, "HIGH" );
System.out.println(high); //HIGH
System.out.println(high.name()); //HIGH
Level03.LOW.show();
Level03.HIGH.show();
}
}
6、枚举注意事项
- 一旦定义了枚举,最好不要妄图修改里面的值,除非修改是必要的; - 枚举类默认继承的是Java.Lang.Enum类而不是Object类 - 枚举类不能有子类,因为其枚举类默认被final修饰 - 只能由private构造方法 - switch中使用枚举时,直接使用常量名,不用携带类名 - 不能定义name属性,因为自带name属性 - 不要为枚举类中的属性提供set方法,不符合枚举最初设计初衷(不可修改)二、注解 1、注解概述
1、Java注解(Annotion)又称Java标注,是jdk5.0引入的一种注释机制 2、区别于注释: - Java标注可以通过反射机制获取标注内容 - 在编译器生成class文件时,标注可以被嵌入字节码中 - JVM虚拟机可以保留标注内容,在运行时获取标注内容 - 支持自定义Java标注 - 注释--给人看 注解--给机器看 3、主要作用 1. 编译格式检查 如@Override检查是否重写父类的方法 2. 反射中解析 3. 生成帮助文档 4. 跟踪代码依赖... 4、学习重点: 1. 概念 2. 如何使用内置注解 3. 怎么自定义注解 4. 反射中怎么获取注解内容2、内置注解(系统已有的)
Java 定义了一套注解,共有 7 个,3 个在 java.lang 中,剩下 4 个在 java.lang.annotation 中。
1. 作用在代码的注解@Override - 检查该方法是否是重写方法(只能是方法)
如果发现其父类,或者是引用的接口中并没有该方法时,会报编译错误。
@Deprecated - 标记过时方法。如果使用该方法,会报编译警告。
@SuppressWarnings - 指示编译器去忽略注解中声明的警告。
三种用法:
1.@SuppressWarnings("unchecked") [抑制单类型的警告]
2.@SuppressWarnings("unchecked","rawtypes") [抑制多类型的警告]
3.@SuppressWarnings("all") [抑制所有类型的警告]
其他参数见下图
2. 作用在其他注解的注解(元注解)
@Retention - 标识这个注解怎么保存,是只在代码中,还是编入class文件中,或者是在运行时可以通过反射访问。 @documented - 标记这些注解是否包含在用户文档中。 @Target - 标记这个注解应该是哪种 Java 成员。 @Inherited - 标记这个注解是继承于哪个注解类(默认 注解并没有继承于任何子类) 1.子类会继承父类使用的注解中被@Inherited修饰的注解 2.接口继承关系中,子接不会继承父类接口中的任何注解,不管父类接口中使用的注解有没有被@Inherited修饰 3.类实现接口时不会继承任何接口中定义的注解3. 从 Java 7 开始,额外添加了 3 个注解
@SafeVarargs - Java 7 开始支持,忽略任何使用参数为泛型变量的方法或构造函数调用产生的警告。 @FunctionalInterface - Java 8 开始支持,标识一个匿名函数或函数式接口。 @Repeatable - Java 8 开始支持,标识某注解可以在同一个声明上使用多次。3、自定义注解 1. 注解架构
- 每 1 个 Annotation 对象,都会有唯一的 RetentionPolicy 属性;至于 ElementType 属性,则有 1~n 个。
- ElementType(注解的用途类型)
package java.lang.annotation;
public enum ElementType{
TYPE,
FIFLD,
METHOD,
PARAMETER,
CONSTRUCTOR,
LOCAL_VARIABLE,
ANNOTION_TYPE,
PACKAGE
}
- RetentionPolicy(注解作用域策略)
package java.lang.annotation;
public enum RetentionPolicy{
SOURCE,
CLASS,
RUNTIME
}
2. 定义格式
@interface 自定义注解名{}
类似类、方法的定义,注解的定义将关键字改成@
3. 注意事项
1. 定义的注解,自动继承了java.lang,annotation.Annotation接口 2. 注解中的每一个方法,实际是声明的注解配置参数 ·方法的名称 -- 配置参数的名称 ·方法的返回值类型 -- 配置参数的类型(只能是基本类型/Class/String/enum) 3. 可以通过default来声明参数的默认值 如 String value default "易拉罐" 4. 如果只有一个参数成员,一般参数名为value 5. 注解元素必须要有值,我们定义注解元素时,经常使用空字符串、0作为默认值。4. 实例展示
@Target(ElementType.TYPE)
@documented
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface MyAnnotion {
String value() default 0;
}
三、反射
1、反射概述
JAVA反射机制是在运行状态中,获取任意一个类的结构,创建对象,得到方法,执行方法,属性! 这种在运行状态动态获取信息以及动态调用对象方法的功能被称为java语言的反射机制。2、类加载器与资源目录
通过类加载器加载资源文件
默认是加载src路径下的文件,但是当项目存放在resource root 目录下,就加载resource root下的文件。
要想了解一个类,必须先要获取到该类的字节码文件对象。
在Java中,每一个字节码文件,被夹在到内存后,都存在一个对应的Class类型的对象
得到Class的几种方式
1.已知类的名称,且类已经存在 包名.类名.class 得到一个类的类对象 2.如果拥有类的对象 Class 对象.getClass() 得到一个类的 类对象 3.已知类的名称 Class.forName(包名+类名) 得到一个类的 类对象4、反射中的构造方法 (1)获取Constructor–通过class对象 获取一个类的构造方法
1. 通过指定的参数类型,获取指定的单个构造方法 getConstructor(参数类型的class对象数组) 例如: Person(String name, int age) Constructor c = p.getClass().getConstructor(String.class, int.class); 2. 获取构造方法数组 getConstructors(); 3. 获取所有权限的单个构造方法 getDeclaredConstructor(参数类型的class对象数组) 4. 获取所有权限的构造方法数组 getDeclaredConstructors();(2) Constructor创建对象
newInstance(Object...para) [参数:是一个Object类型可变参数,传递的参数顺序必须匹配构造方法中形式参数列表的顺序] setAccessible(boolean flag) flag = true 表示忽略访问权限检查(3)练习
Person.java
package demoAnnotion_01;
public class Person {
private String name;
private int age;
public Person() {
}
//私有的构造方法
private Person(String name){
this.name = name;
this.age = 100;
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + ''' +
", age=" + age +
'}';
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
package demoAnnotion_01;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
public class DemoPerson {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
//1.获取Person类的类对象 -- 把Person加载到内存
Class pClass = (Class)Class.forName( "demoAnnotion_01.Person" );
//方法一 :获取类对象的无参构造方法
Constructor c01 = pClass.getConstructor();
//通过获取到的无参构造方法创建一个Person对象
Person p01 = c01.newInstance();
System.out.println(p01); //Person{name='null', age=0}
//方法二:获取类对象的全参构造方法
Constructor c02 = pClass.getConstructor(String.class, int.class);
//通过获取到的全参构造方法创建一个Person对象
Person p02 = c02.newInstance("易拉罐",21);
System.out.println(p02); //Person{name='易拉罐', age=21}
//方法三:获取类对象的所有权限(包括public修饰)的构造方法
Constructor c03 = pClass.getDeclaredConstructor( String.class );
c03.setAccessible( true );
Person p03 = c03.newInstance( "Eva's family" );
System.out.println(p03); //Person{name='Eva's family', age=100}
}
}
5、反射中的方法
(1)通过class对象 获取一个类的方法
1.根据参数列表的类型和方法名,得到一个方法(public修饰的) getMethod(StringmethodName,class..clss) 2.得到一个类的所有方法(public修饰的) getMethods(); 3.根据参数列表的类型和方法名,得到一个方法(除继承以外所有的:包含私有,共有,保护,默认) getDeclaredMethod(StringmethodName,class..clss) 4.得到一个类的所有方法(除继承以外所有的:包含私有,共有,保护,默认) getDeclaredMethods();(2)Method执行方法
invoke(Object o, Object...para): 参数1. 要调用方法的对象 参数2:要传递的参数列表 getName() 获取参数的方法名称 setAccessiable(boolean flag)(3)练习
//1.获取Person类的类对象 -- 把Person加载到内存
Class pClass = (Class)Class.forName( "demoAnnotion_01.Person" );
//2. 获取类对象的构造方法,并创建类对象
//方法一 :获取类对象的无参构造方法
Constructor c01 = pClass.getConstructor();
//通过获取到的无参构造方法创建一个Person对象
Person p01 = c01.newInstance();
System.out.println(p01); //Person{name='null', age=0}
//3. 获取类的方法
Method setName = pClass.getMethod( "setName", String.class );
Method setAge = pClass.getMethod( "setAge", int.class );
//Method执行方法
setName.invoke( p01, "zqd" );
setAge.invoke( p01, 23 );
System.out.println(p01); //Person{name='zqd', age=23}
6、反射中的属性
(1)通过class对象 获取一个类的属性
1.根据属性的名称,获取一个属性对象(public修饰) getField(String filedName) 2.获取一个类的所有属性(public修饰的) getFields(); 3.根据属性的名称,获取一个属性对象(所有属性) getDeclaredField(String filedName) 4.获取所有属性 getDeclaredFileds();(2)Field属性的对象类型
1.get(Object o ) 参数:要获取属性的对象 获取指定对象的此属性值 2.set(Object o,Object value); 参数1. 要设置属性值的 对象 参数2. 要设置的属性值 3. getName() 获取属性的名称 4. setAccessible(boolean flag)7、获取注解信息
ORM框架 -- Object Relationship Mapping 对象关系映射 类 -- 数据库(1)获取类/属性/方法的全部注解对象`
Annotation[] annotations01 = Class/Field/Method.getAnnotations();
for(Annotationannotation:annotations01){
System.out.println(annotation);
}
(2) 根据类型获取类/属性/方法的注解对象
注解类型对象名 = (注解类型) c.getAnnotation(注解类型.class);四、内省 1、简介
基于反射,java所提供的一套应用到JavaBean的API 一个定义在包中的类: 拥有无参构造器 所有属性提供get/set方法 所有属性私有 实现了序列化接口 这种类称为bean类 Java提供了一套java.beans包的api,对于反射的操作,进行了封装!2、Introspector
获取Bean类信息方法: BeanInfo getBeanInfo(Class cls) 通过传入的类信息,得到这个Bean类的封装对象3、BeanInfo
常用方法: MethodDescriptor[] getPropertyDescriptors():获取bean类的ger/set方法 数组4、MethodDescriptor
常用方法: 1.Method getReadMehtod(); // 获取一个get方法 2.Method getWriteMethod(); //获取一个set方法 有可能返回null 记得加判断!5、案例展示
Express.java
package demoBean;
import java.io.Serializable;
public class Express implements Serializable {
private String number;
private String name;
private String phoneNumber;
private String address;
private boolean flag;
public Express() {
}
@Override
public String toString() {
return "Express{" +
"number='" + number + ''' +
", name='" + name + ''' +
", phoneNumber='" + phoneNumber + ''' +
", address='" + address + ''' +
", flag=" + flag +
'}';
}
public String getNumber() {
return number;
}
public void setNumber(String number) {
this.number = number;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPhoneNumber() {
return phoneNumber;
}
public void setPhoneNumber(String phoneNumber) {
this.phoneNumber = phoneNumber;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public boolean isFlag() {
return flag;
}
public void setFlag(boolean flag) {
this.flag = flag;
}
}
Demo01.java
package demoBean;
import java.beans.*;
public class Demo01 {
public static void main(String[] args) throws IntrospectionException {
//获取Express类
Class c = Express.class;
//获取Express这个Bean类的封装对象
BeanInfo beanInfo = Introspector.getBeanInfo( c );
//获取属性
PropertyDescriptor[] pds = beanInfo.getPropertyDescriptors();
//循环遍历
for (PropertyDescriptor pd:pds){
System.out.println("属性" + pd.getName() + "的get方法:" + pd.getReadMethod());
System.out.println("属性" + pd.getName() + "的set方法:" + pd.getWriteMethod());
System.out.println("属性对应的类型:" + pd.getPropertyType());
}
}
}
输出结果:
属性address的get方法:public java.lang.String demoBean.Express.getAddress() 属性address的set方法:public void demoBean.Express.setAddress(java.lang.String) 属性对应的类型:class java.lang.String 属性class的get方法:public final native java.lang.Class java.lang.Object.getClass() 属性class的set方法:null 属性对应的类型:class java.lang.Class 属性flag的get方法:public boolean demoBean.Express.isFlag() 属性flag的set方法:public void demoBean.Express.setFlag(boolean) 属性对应的类型:boolean 属性name的get方法:public java.lang.String demoBean.Express.getName() 属性name的set方法:public void demoBean.Express.setName(java.lang.String) 属性对应的类型:class java.lang.String 属性number的get方法:public java.lang.String demoBean.Express.getNumber() 属性number的set方法:public void demoBean.Express.setNumber(java.lang.String) 属性对应的类型:class java.lang.String 属性phoneNumber的get方法:public java.lang.String demoBean.Express.getPhoneNumber() 属性phoneNumber的set方法:public void demoBean.Express.setPhoneNumber(java.lang.String) 属性对应的类型:class java.lang.String



