枚举
为了间接的表示一些固定的值,Java就给我们提供了枚举是指将变量的值一一列出来,变量的值只限于列举出来的值的范围内
定义格式
1 2 3 4 5 6 7 8
| public enum s { 枚举项1,枚举项2,枚举项3; } 注意: 定义枚举类要用关键字enum
public enum Season { SPRING,SUMMER,AUTUMN,WINTER; }
|
示例代码
1 2 3 4 5 6 7 8 9 10 11
| public enum Season { SPRING("春"),SUMMER,AUTUMN,WINTER("冬"); private String s =null; private SeasonEnum(){} private SeasonEnum(String s){ this.s = s; } public String getS(){ return s; } }
|
1 2 3 4 5
| public class Test { public static void main(String[] args) { System.out.println(Season.SPRING.getS()); } }
|
枚举的特点
- 特点
- 所有枚举类都是Enum的子类
- 我们可以通过”枚举类名.枚举项名称”去访问指定的枚举项
- 每一个枚举项其实就是该枚举的一个对象
- 枚举也是一个类,也可以去定义成员变量
1 2 3 4 5 6 7 8 9
| public class Test { public static void main(String[] args) { System.out.println(Season.SPRING); System.out.println(Season.SUMMER); System.out.println(Season.AUTUMN); System.out.println(Season.WINTER); Season spring = Season.SPRING; } }
|
枚举的方法
方法名 |
说明 |
String name() |
获取枚举项的名称 |
int ordinal() |
返回枚举项在枚举类中的索引值 |
int compareTo(E o) |
比较两个枚举项,返回的是索引值的差值 |
String toString() |
返回枚举常量的名称 |
static T valueOf(Class type,String name) |
获取指定枚举类中的指定名称的枚举值 |
values() |
获得所有的枚举项 |
1 2 3
| public enum SeasonEnum { SPRING,SUMMER,AUTUMN,WINTER; }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| public class EnumDemo { public static void main(String[] args) { String name = SeasonEnum.SPRING.name(); System.out.println(name); System.out.println("=============="); int index1 = SeasonEnum.SPRING.ordinal(); int index2 = SeasonEnum.SUMMER.ordinal(); int index3 = SeasonEnum.AUTUMN.ordinal(); int index4 = SeasonEnum.WINTER.ordinal(); System.out.println(index1); System.out.println(index2); System.out.println(index3); System.out.println(index4); System.out.println("=============="); int result = SeasonEnum.SPRING.compareTo(SeasonEnum.WINTER); System.out.println(result); System.out.println("==========="); String str = SeasonEnum.SPRING.toString(); System.out.println(str); System.out.println("=========="); SeasonEnum spring = Enum.valueOf(SeasonEnum.class, "SPRING"); System.out.println(spring); System.out.println(SeasonEnum.SPRING == spring); System.out.println("========="); SeasonEnum[] values = SeasonEnum.values(); for (SeasonEnum value:values) { System.out.println(value); } } }
|
注解
概述
注解和注释的区别
使用注解进行配置配置的优势
java中的类,方法,变量,参数和包等都可以被标注。它们可以在编译、类加载、运行时被读取并执行相应的处理。
基本注解用法:
@Override 检查该方法是否是重写方法。如果发现其父类,或者是引用的接口中并没有该方法时,会报编译错误。
@Deprecated 标识方法过时 如果使用该方法,会报编译警告。
@SuppressWarnings 抑制警告,指示编译器去忽略注解中声明的警告。
自定义注解
格式
1 2 3 4 5
| public @interface 注解名称 {
public 属性类型 属性名() default 默认值 ;
}
|
属性类型:基本数据类型,String,Class,注解,枚举,以上类型的一维数组
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| public @interface AnnoTest { public char ch() default '好'; int sum() default 1; String str() default "好人"; String[] starr() default {"h","a","o"}; Season season() default Season.SPRING; Anno anno() default @Anno; Class clazz() default SeasonTest.class;
public String value(); }
public @interface Anno {}
public enum Season { SPRING,SUMMER,AUTUMN,WINTER; }
|
注意:如果只有一个属性需要赋值,并且属性的名称是value,则value可以省略,直接定义值即可
自定义注解案例
需求
- 自定义一个注解@Test,用于指定类的方法上,如果某一个类的方法上使用了该注解,就执行该方法
实现步骤
- 自定义一个注解Test,并在类中的某几个方法上加上注解
- 在测试类中,获取注解所在的类的Class对象
- 获取类中所有的方法对象
- 遍历每一个方法对象,判断是否有对应的注解
代码实现
1 2 3 4 5 6 7 8 9 10 11
|
@Retention(RetentionPolicy.RUNTIME) public @interface Anno { }
|
1 2 3 4 5 6 7 8 9 10 11
| public class Utils { public void hao(){ System.out.println("好人"); } @Anno public void method(){ System.out.println("启动"); } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| public class Test { public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, InvocationTargetException, NoSuchMethodException { Class clazz = Class.forName("com.example.qy161_backstage.Utils"); Utils utils = (Utils) clazz.getDeclaredConstructor().newInstance(); Method[] method = clazz.getDeclaredMethods(); for (Method methods : method) {
if (methods.isAnnotationPresent(Anno.class)){ methods.invoke(utils); } } } }
|
元注解
概述
元注解名 |
说明 |
@Target |
指定了注解能在哪里使用 |
@Retention |
可以理解为保留时间(生命周期) |
@Inherited |
表示修饰的自定义注解可以被子类继承 |
@Documented |
表示该自定义注解,会出现在API文档里面 |
1 2 3 4 5 6 7 8
|
@Target({ElementType.FIELD,ElementType.TYPE,ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) public @interface Anno {}
|
1 2 3
| @Anno public class Person { }
|
1 2 3 4 5
| public class Student extends Person { public void show(){ System.out.println("student.......show.........."); } }
|
1 2 3 4 5 6 7 8 9
| public class StudentDemo { public static void main(String[] args) throws ClassNotFoundException { Class clazz = Class.forName("com.aaa.myanno4.Student"); boolean result = clazz.isAnnotationPresent(Anno.class); System.out.println(result); } }
|
反射
反射概念:
类加载器
负责将.class文件(存储的物理文件)加载在到内存中
xxx.java –javac–> xxx.class –(类加载器)–>虚拟机
类加载的过程【理解】
类加载时机
- 创建类的实例(对象)–> new
- 调用类的类方法 – >静态方法
- 访问类或者接口的类变量,或者为该类变量赋值 –>静态变量
- 使用反射方式来强制创建某个类或接口对应的java.lang.Class对象–> 反射
- 初始化某个类的子类 –> 创建子类
- 直接使用java.exe命令来运行某个主类 –> main 函数
类加载过程
- 加载
- 通过包名 + 类名,获取这个类
- 把这个类加载到内存中
- 加载完毕创建一个class对象
- 链接
- 验证:确保Class文件字节流中包含的信息符合当前虚拟机的要求,并且不会危害虚拟机自身安全(文件中的信息是否符合虚拟机规范有没有安全隐患)
- 准备:负责为类的类变量(被static修饰的变量)分配内存,并设置默认初始化值,(初始化静态变量)
- 解析:将类的二进制数据流中的符号引用替换为直接引用(本类中如果用到了其他类,此时就需要找到对应的类)
- 初始化
- 根据程序员通过程序制定的主观计划去初始化类变量和其他资源,(静态变量赋值以及初始化其他资源)
小结
当一个类被使用的时候,才会加载到内存
类加载的过程: 加载、验证、准备、解析、初始化
类加载的分类【理解】
- 分类
- Bootstrap class loader:虚拟机的内置类加载器,通常表示为null ,并且没有父null 启动类加载器
- Platform class loader:平台类加载器,负责加载JDK中一些特殊的模块在,Java8和之前,这个加载器叫做扩展加载器(ExtClassLoader)
- System class loader:系统类加载器,负责加载用户类路径上所指定的类库,也叫Appclass Loader
- 类加载器的继承关系
- System的父加载器为Platform
- Platform的父加载器为Bootstrap
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| public class ClassLoaderTest { public static void main(String[] args) { ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader(); ClassLoader parent = systemClassLoader.getParent(); ClassLoader parent1 = parent.getParent();
System.out.println("系统类加载器" + systemClassLoader); System.out.println("平台类加载器" + parent); System.out.println("启动类加载器" + parent1); } }
|
双亲委派模型【理解】
概念:如果一个类加载器收到了类加载请求,它并不会自己先去加载,而是把这个请求委托给父类的加载器去执行,如果父类加载器还存在其父类加载器,则进一步向上委托,依次递归,请求最终将到达顶层的启动类加载器,如果父类加载器可以完成类加载任务,就成功返回,倘若父类加载器无法完成此加载任务,子加载器才会尝试自己去加载,这就是双亲委派模式
ClassLoader类
方法名 |
说明 |
public static ClassLoader getSystemClassLoader() |
获取系统类加载器 |
public InputStream getResourceAsStream(String name) |
加载某一个资源文件 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| public class ClassLoaderDemo2 { public static void main(String[] args) throws IOException {
ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
InputStream is = systemClassLoader.getResourceAsStream("prop.properties"); Properties prop = new Properties(); prop.load(is); System.out.println(prop); is.close(); } }
|
Class类
Class基本概念
java.lang.Class类的实例可以用于描述Java应用程序中的类和接口,也就是一种数据类型。 该类没有公共构造方法,该类的实例由Java虚拟机和类加载器自动构造完成,本质上就是加载到内存中的运行时类。
获取Class对象的方式
使用数据类型.class的方式可以获取对应类型的Class对象(掌握)。
使用引用/对象.getClass()的方式可以获取对应类型的Class对象。
使用包装类.TYPE的方式可以获取对应基本数据类型的Class对象。
使用Class.forName()的方式来获取参数指定类型的Class对象(掌握)。
使用类加载器ClassLoader的方式获取指定类型的Class对象。
常用的方法
方法声明 |
功能介绍 |
static Class<?> forName(String className) |
用于获取参数指定类型对应的Class对象并返回 |
T newInstance() [方法已过时] |
用于创建该Class对象所表示类的新实例 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| public class ClassTest { public static void main(String[] args) throws ClassNotFoundException { Class c1 = String.class; System.out.println("c1:"+c1); c1= int.class; System.out.println("c1: "+c1); c1 = void.class; System.out.println("c1: "+c1); System.out.println("============="); String str1 = new String("hello"); c1=str1.getClass(); System.out.println("c1: "+c1); Integer it1 = 20; c1 = it1.getClass(); System.out.println("c1: "+c1); System.out.println("============="); c1 = Class.forName("java.util.Date"); System.out.println("c1: "+c1); System.out.println("============="); ClassLoader classLoader = ClassTest.class.getClassLoader(); System.out.println("classLoader = " + classLoader); c1 = classLoader.loadClass("java.lang.String"); System.out.println("c1 = " + c1);
} }
|
Constructor类
概念:java.lang.reflect.Constructor类主要用于描述获取到的构造方法信息
Class类获Constructor类的方法
方法声明 |
功能介绍 |
Constructor getConstructor(Class<>…parameterTypes) |
用于获取此Class对象所表示类型中参数指定的 |
Constructor<?>0getConstructors() |
用于获取此Class对象所表示类型中所有的公共 |
Constructor类的常用方法
方法声明 |
功能介绍 |
T newInstance(Object…initargs) |
使用此Constructor对象描述的构造方法来构造Class对象代表类型的新实例 |
int getModifiers() |
获取方法的访问修饰符 |
String getName() |
获取方法的名称 |
Class<?[]getParameterTypes() |
获取方法所有参数的类型 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| public class Person { private String name; public Person() {}
public Person(String name) { this.name = name; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
@Override public String toString() { return "Person{" + "name='" + name + '\'' + '}'; } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| public class ConstructorTest { public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException { Person person = new Person(); Class aClass = Class.forName("com.example.qy161_backstage.reflex.Person"); Constructor constructors = aClass.getConstructor(); Object o = constructors.newInstance(); System.out.println(o); Person person1 = new Person("hd"); Class aClass1 = Class.forName("com.example.qy161_backstage.reflex.Person"); Constructor constructors1 = aClass.getConstructor(String.class); Object hd1 = constructors1.newInstance("hd1"); System.out.println(hd1); Person person2 = new Person(); Class aClass2 = Class.forName("com.example.qy161_backstage.reflex.Person"); Constructor[] constructors2 = aClass2.getConstructors(); for (int i = 0; i < constructors2.length; i++) { Constructor constructor = constructors2[i]; System.out.println(constructor); System.out.println("=========================="); System.out.println(constructor.getModifiers()); System.out.println(constructor.getName()); System.out.println(constructor.getParameterTypes()); } } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
| public class PersonConstructorTest { public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException { Person p1 = new Person(); System.out.println("无参方式创建的对象是:" + p1); System.out.println("-------------------------------");
BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream("E:/.Code/aaa.txt"))); String str1 = br.readLine(); Class c1 = Class.forName(str1); Constructor constructor = c1.getConstructor(); System.out.println("无参方式创建的对象是:" + constructor.newInstance()); br.close(); System.out.println("-------------------------------"); Constructor constructor1 = c1.getConstructor(String.class); System.out.println("有参方式构造的对象是:" + constructor1.newInstance("zhangfei")); System.out.println("-------------------------------"); Constructor[] constructors = c1.getConstructors(); for (Constructor ct : constructors) { System.out.println("构造方法的访问修饰符是:" + ct.getModifiers()); System.out.println("构造方法的方法名称是:" + ct.getName()); Class[] parameterTypes = ct.getParameterTypes(); System.out.print("构造方法的所有参数类型是:"); for (Class cs : parameterTypes) { System.out.print(cs + " "); } System.out.println(); System.out.println("-------------------------------"); } } }
|
Field类
基本概念:java.lang.reflect.Field类主要用于描述获取到的单个成员变量信息
获取到Field类的方法
方法声明 |
功能介绍 |
Field getDeclaredField(String name) |
用于获取此Class对象所表示类中参数指定的单个成员变量信息 |
Field[ getDeclaredFields() |
用于获取此Class对象所表示类中所有成员变量信息 |
Field类的常用方法
方法声明 |
功能介绍 |
Object get(Object obj) |
获取参数对象obj中此Field对象所表示成员变量的数值 |
void set(Object obj, object value) |
将参数对象obj中此Field对象表示成员变量的数值修改为参数value的数值 |
void setAccessible(boolean flag) |
当实参传递true时,则反射对象在使用时应该取消Java语言访问检查 |
int getModifiers() |
获取成员变量的访问修饰符 |
Class<?> getType() |
获取成员变量的数据类型 |
String getName() |
获取成员变量的名称 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| public class FieldTest { public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchFieldException {
Class aClass = Class.forName("com.example.qy161_backstage.reflex.Person"); Constructor constructor = aClass.getConstructor(String.class); Object name = constructor.newInstance("name"); Field declaredField = aClass.getDeclaredField("name"); declaredField.setAccessible(true); System.out.println("获取到的成员变量数值为:" + declaredField.get(name)); declaredField.set(name,"zhangfei"); System.out.println(declaredField.get(name)); System.out.println("======================"); Field[] declaredField1 = aClass.getDeclaredFields(); for (Field d: declaredField1) { System.out.println("获取到的访问修饰符为:" + d.getModifiers()); System.out.println("获取到的数据类型为:" + d.getType()); System.out.println("获取到的成员变量名称是:" + d.getName()); }
} }
|
Method类
基本概念:java.lang.reflect.Method类主要用于描述获取到的单个成员方法信息
获取到Method类的方法
方法声明 |
功能介绍 |
Method getMethod(String name,Class<?>… parameterTypes) |
用于获取该Class对象表示类中名字为name参数为parameterTypes的指定公共成员方法 |
MethodgetMethods() |
用于获取该Class对象表示类中所有公共成员方法 |
Method类的常用方法
方法声明 |
功能介绍 |
object invoke(Object obj,Object… args) |
使用对象obj来调用此Method对象所表示的成员方法,实参传递args |
int getModifiers() |
获取方法的访问修饰符 |
Class<?> getReturnType() |
获取方法的返回值类型 |
String getName() |
获取方法的名称 |
Class<?>getParameterTypes() |
获取方法所有参数的类型 |
Class<?>-getExceptionTypes() |
获取方法的异常信息 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| public class MethodTest { public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException { Class c1 = Class.forName("com.example.qy161_backstage.reflex.Person"); Constructor constructor = c1.getConstructor(String.class); Object object = constructor.newInstance("zhangfei"); Method method = c1.getMethod("getName"); System.out.println("调用方法的返回值是:" + method.invoke(object)); Method[] methods = c1.getMethods(); for (Method mt : methods) { System.out.println("成员方法的修饰符是:" + mt.getModifiers()); System.out.println("成员方法的返回值类型是:" + mt.getReturnType()); System.out.println("成员方法的名称是:" + mt.getName()); System.out.println("成员方法形参列表的类型是:"); Class<?>[] parameterTypes = mt.getParameterTypes(); for (Class ct : parameterTypes) { System.out.print(ct + " "); } System.out.println("成员方法的异常类型列表是:"); Class<?>[] exceptionTypes = mt.getExceptionTypes(); for (Class ct: exceptionTypes) { System.out.print(ct + " "); } }
} }
|
获取其它结构信息
方法声明 |
功能介绍 |
Package getPackage() |
获取所在的包信息 |
Class<? super T> getSuperclass() |
获取继承的父类信息 |
Class<?>[] getInterfaces() |
获取实现的所有接口 |
AnnotationgetAnnotations() |
获取注解信息 |
TypegetGenericInterfaces() |
获取泛型信息 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| public class Person { private String name; private int age; public Person() {}
public Person(String name) { this.name = name; } public Person(String name,int age) { this.name = name; this.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; }
@Override public String toString() { return "Person{" + "name='" + name + '\'' + ", age=" + age + '}'; } }
|
1 2 3
| @Retention(RetentionPolicy.RUNTIME) public @interface MyAnnotation { }
|
1 2 3 4 5 6 7 8
| @MyAnnotation public class Student <T,E> extends Person implements Comparable, Serializable {
@Override public int compareTo(Object o) { return 0; } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| public class StudentTest { public static void main(String[] args) throws ClassNotFoundException { Class c1 = Class.forName("com.example.qy161_backstage.reflex.Student"); System.out.println("获取到的包信息是:" + c1.getPackage()); System.out.println("获取到的父类信息是:" + c1.getSuperclass()); System.out.println("获取到的接口信息是:"); Class[] interfaces = c1.getInterfaces(); for (Class ct : interfaces) { System.out.print(ct + " "); } System.out.println(); System.out.println("获取到的注解信息是:"); Annotation[] annotations = c1.getAnnotations(); for (Annotation at : annotations) { System.out.print(at + " "); } System.out.println(); System.out.println("获取到的泛型信息是:"); Type[] genericInterfaces = c1.getGenericInterfaces(); for (Type tt : genericInterfaces) { System.out.print(tt + " "); } System.out.println(); } }
|