1、枚举
1.1、简介
JDK1.5
引入了新的类型
——
枚举。
在
JDK1.5
之前,我们定义常量都是:
public static fianl....
。很难管理。
枚举,可以把相关的常量分组到一个枚举类型里,而且枚举提供了比常量更多的方法。
用于定义有限数量的一组同类常量,例如:
错误级别:
低、中、高、急
一年的四季:
春、夏、秋、冬
商品的类型:
美妆、手机、电脑、男装、女装
...
在枚举类型中定义的常量是该枚举类型的实例。
1.2、定义格式
权限修饰符
enum
枚举名称
{
实例
1,
实例
2
,实例
3
,实例
4;
}
例如:
public enum Level1 {
LOW(30), MEDIUM(15), HIGH(7), URGENT(1);
private int levelValue;
private Level1(int levelValue) {
this.levelValue=levelValue;
}
public int getLevelValue() {
return levelValue;
}
public void setLevelValue(int levelValue) {
this.levelValue = levelValue;
}
}
在JDK1.5之前。
public static final Level LOW = new Level(1);
public static final Level MIDDLE = new Level(2);
public static final Level HIGE = new Level(3);
private int levelValue;
public Level(int levelValue) {
this.levelValue=levelValue;
}
public int getLevelValue() {
return levelValue;
}
public void setLevelValue(int levelValue) {
this.levelValue = levelValue;
}
1.3、枚举类的主要方法
1.4、实现接口的枚举类
所有的枚举都继承自
java.lang.Enum
类。由于
Java
不支持多继承,所以枚举对象不能再继承其他类。
每个枚举对象,都可以实现自己的抽象方法
public enum Level2 implements LShow{
LOW(){
@Override
public void show() {
System.out.println("低级别对象在调用show方法");
}
},HIGE(){
@Override
public void show() {
System.out.println("高级别对象在调用show方法");
}
}
}
interface LShow{
void show();
}
1.5、注意事项
- 一旦定义了枚举,最好不要妄图修改里面的值,除非修改是必要的。
- 枚举类默认继承的是java.lang.Enum类而不是Object类
- 枚举类不能有子类,因为其枚举类默认被fifinal修饰
- 只能有private构造方法
- switch中使用枚举时,直接使用常量名,不用携带类名
- 不能定义name属性,因为自带name属性
- 不要为枚举类中的属性提供set方法,不符合枚举最初设计初衷。
2、注解
2.1、简介
Java
注解(
Annotation
)又称
Java
标注,是
JDK5.0
引入的一种注释机制。
Java
语言中的类、方法、变量、参数和包等都可以被标注。和注释不同,
Java
标注可以通过反射获取标
注内容。在编译器生成类文件时,标注可以被嵌入到字节码中。
Java
虚拟机可以保留标注内容,在运行
时可以获取到标注内容 。 当然它也支持自定义
Java
标注。
主要用于:
编译格式检查
反射中解析
生成帮助文档
跟踪代码依赖等
2.2、学习的重点
1.
概念
2.
怎么使用内置注解
3.
怎么自定义注解
4.
反射中怎么获取注解内容
2.3、内置注解
@Override : 重写 *
定义在java.lang.Override
@Deprecated:废弃 *
定义在java.lang.Deprecated
@SafeVarargs
Java 7 开始支持,忽略任何使用参数为泛型变量的方法或构造函数调用产生的警告。
@FunctionalInterface: 函数式接口 *
Java 8 开始支持,标识一个匿名函数或函数式接口
@Repeatable:标识某注解可以在同一个声明上使用多次
Java 8
开始支持,标识某注解可以在同一个声明上使用多次。
SuppressWarnings:抑制编译时的警告信息。 *
定义在
java.lang.SuppressWarnings
三种使用方式
1. @SuppressWarnings("unchecked") [^
抑制单类型的警告
]
2. @SuppressWarnings("unchecked","rawtypes") [^
抑制多类型的警告
]
3. @SuppressWarnings("all") [^
抑制所有类型的警告
]
参数列表:
2.4、元注解
2.4.1、简介
作用在其他注解的注解
2.4.2、有哪些?
@Retention -
标识这个注解怎么保存,是只在代码中,还是编入
class
文件中,或者是在运行时可
以通过反射访问。
@Documented -
标记这些注解是否包含在用户文档中
javadoc
。
@Target -
标记这个注解应该是哪种
Java
成员。
@Inherited -
标记这个注解是自动继承的
2.5、自定义注解
2.5.1、注解架构
01) Annotation
与
RetentionPolicy
与
ElementType
。
每
1
个
Annotation
对象,都会有唯一的
RetentionPolicy
属性;至于
ElementType
属性,则有
1~n 个。
(02) ElementType(
注解的用途类型
)
"
每
1
个
Annotation"
都与
"1
~
n
个
ElementType"
关联。当
Annotation
与某个
ElementType
关联
时,就意味着:
Annotation
有了某种用途。例如,若一个
Annotation
对象是
METHOD
类型,则该
Annotation
只能用来修饰方法
(03) RetentionPolicy
(注解作用域策略)。
"
每
1
个
Annotation"
都与
"1
个
RetentionPolicy"
关联。
a)
若
Annotation
的类型为
SOURCE
,则意味着:
Annotation
仅存在于编译器处理期间,编译器
处理完之后,该
Annotation
就没用了。 例如,
" @Override"
标志就是一个
Annotation
。当它修
饰一个方法的时候,就意味着该方法覆盖父类的方法;并且在编译期间会进行语法检查!编译器处
理完后,
"@Override"
就没有任何作用了。
b)
若
Annotation
的类型为
CLASS
,则意味着:编译器将
Annotation
存储于类对应的
.class
文件
中,它是
Annotation
的默认行为。
c)
若
Annotation
的类型为
RUNTIME
,则意味着:编译器将
Annotation
存储于
class
文件中,并
且可由
JVM
读入。
3、反射
3.1、概述
JAVA
反射机制是在运行状态中,获取任意一个类的结构
,
创建对象
,
得到方法,执行方法
,
属性
!
这种在运行状态动态获取信息以及动态调用对象方法的功能被称为
java
语言的反射机制。
3.2、类加载器
JAVA
反射机制是在运行状态中,获取任意一个类的结构
,
创建对象
,
得到方法,执行方法
,
属性
!
这种在运行状态动态获取信息以及动态调用对象方法的功能被称为
java
语言的反射机制。
Java
类加载器(
Java Classloader
)是
Java
运行时环境(
Java Runtime Environment
)的一部分,
负责动态加载
Java
类到
Java
虚拟机的内存空间中。
java
默认有三种类加载器,
BootstrapClassLoader
、
ExtensionClassLoader
、
App
ClassLoader
。
BootstrapClassLoader
(引导启动类加载器):
嵌在
JVM
内核中的加载器,该加载器是用
C++
语言写的,主要负载加载
JAVA_HOME/lib
下的类库,引 导启动类加载器无法被应用程序直接使用。
ExtensionClassLoader
(扩展类加载器):
ExtensionClassLoader
是用
JAVA
编写,且它的父类加载器是
Bootstrap
。
是由
sun.misc.Launcher$ExtClassLoader
实现的,主要加载
JAVA_HOME/lib/ext
目录中的类
库。
它的父加载器是
BootstrapClassLoader
App ClassLoader
(应用类加载器):
App ClassLoader
是应用程序类加载器,负责加载应用程序
classpath
目录下的所有
jar
和
class
文
件。它的父加载器为
Ext ClassLoader
类通常是按需加载,即第一次使用该类时才加载。由于有了类加载器,
Java
运行时系统不需要知道文件与
文件系统。学习类加载器时,掌握
Java
的委派概念很重要。
双亲委派模型:如果一个类加载器收到了一个类加载请求,它不会自己去尝试加载这个类,而是把这个请求
转交给父类加载器去完成。每一个层次的类加载器都是如此。因此所有的类加载请求都应该传递到最顶层的
启动类加载器中,只有到父类加载器反馈自己无法完成这个加载请求(在它的搜索范围没有找到这个类)
时,子类加载器才会尝试自己去加载。委派的好处就是避免有些类被重复加载
3.3、所有类型的Class对象
在
Java
中,每一个字节码文件,被夹在到内存后,都存在一个对应的
Class
类型的对象
3.4、得到Class的几种方式
1.
如果在编写代码时
,
指导类的名称
,
且类已经存在
,
可以通过
包名
.
类名
.class
得到一个类的 类对象
//1. 通过包名.类名.class 加载类
Class<person> c1 = person.class;
System.out.println(c1);
2.
如果拥有类的对象
,
可以通过
Class
对象
.getClass()
得到一个类的 类对象
//2. 通过类的对象获取类的信息
person p = new person();
Class<person> c2 = (Class<person>) p.getClass();
System.out.println(c2);
3.
如果在编写代码时
,
知道类的名称
,
可以通过
Class.forName(
包名
+
类名
):
得到一个类的 类对象
//3.
Class<person> c3 = (Class<person>) Class.forName("Demo.person");
System.out.println(c3);
上述的三种方式
,
在调用时
,
如果类在内存中不存在
,
则会加载到内存
!
如果类已经在内存中存在
,
不
会重复加载
,
而是重复利用
!
3.5、获取Constructor
3.5.1、通过class对象 获取一个类的构造方法
//找到无参构造方法
Constructor<person> c1 = pClass.getConstructor();
//使用无参构造方法创建对象
person p = c1.newInstance();
System.out.println(p);
1.
通过指定的参数类型
,
获取指定的单个构造方法
getConstructor(
参数类型的
class
对象数组
)
例如
:
构造方法如下
: Person(String name,int age)
得到这个构造方法的代码如下
:
Constructor c = p.getClass().getConstructor(String.class,int.class);
2.
获取构造方法数组
getConstructors();
3.
获取所有权限的单个构造方法
getDeclaredConstructor(
参数类型的
class
对象数组
)
4.
获取所有权限的构造方法数组
getDeclaredConstructors();
3.5.2、Constructor 创建对象
Class c = Class.forName("Demo.person");
Constructor o = c.getConstructor();
Object p = o.newInstance();
Field phoneNumber= c.getField("phoneNumber");;
phoneNumber.set(p,"17812341234");
Field name= c.getDeclaredField("name");;
name.setAccessible(true);
phoneNumber.set(p,"王十");
System.out.println(p);
常用方法
:
newInstance(Object... para)
调用这个构造方法
,
把对应的对象创建出来
参数
:
是一个
Object
类型可变参数
,
传递的参数顺序 必须匹配构造方法中形式参数列表的顺
序
!
setAccessible(boolean flag)
如果
flag
为
true
则表示忽略访问权限检查
!(
可以访问任何权限的方法
)
3.6、获取Method
//加载类
Class c1 = Class.forName("Demo.person");
//获取类的构造方法
Constructor c = c1.getConstructor();
//创建了对象
Object p = c.newInstance();
//获取类的方法
Method setName = c1.getMethod("setName", String.class);
Method setAge = c1.getMethod("setAge", int.class);
setAge.setAccessible(true);
//参数一 那个对象要执行setName方法
//参数二 调用方法时传递的参数0-n
setName.invoke(p,"张三");
setAge.invoke(p,20);
System.out.println(p);
3.6.1、通过class对象 获取一个类的方法
1. getMethod(String methodName , class.. clss)
根据参数列表的类型和方法名
,
得到一个方法
(public
修饰的
)
2. getMethods();
得到一个类的所有方法
(public
修饰的
)
3. getDeclaredMethod(String methodName , class.. clss)
根据参数列表的类型和方法名
,
得到一个方法
(
除继承以外所有的
:
包含私有
,
共有
,
保护
,
默认
)
4. getDeclaredMethods();
得到一个类的所有方法
(
除继承以外所有的
:
包含私有
,
共有
,
保护
,
默认
)
3.6.2、Method 执行方法
invoke(Object o,Object... para) :
调用方法
,
参数
1.
要调用方法的对象
参数
2.
要传递的参数列表
getName()
获取方法的方法名称
setAccessible(boolean flag)
如果
flag
为
true
则表示忽略访问权限检查
!(
可以访问任何权限的方法
)
3.7、获取Field
Class c = Class.forName("Demo.person");
Constructor o = c.getConstructor();
Object p = o.newInstance();
Field phoneNumber= c.getField("phoneNumber");;
phoneNumber.set(p,"17812341234");
Field name= c.getDeclaredField("name");;
name.setAccessible(true);
phoneNumber.set(p,"王十");
System.out.println(p);
3.7.1、通过class对象 获取一个类的属性
1. getDeclaredField(String filedName)
根据属性的名称
,
获取一个属性对象
(
所有属性
)
2. getDeclaredFields()
获取所有属性
参数
1.
要设置属性值的 对象
参数
2.
要设置的值
设置指定对象的属性的值
3. getField(String filedName)
根据属性的名称
,
获取一个属性对象
(public
属性
)
4. getFields()
获取所有属性
(public)
3.7.2、Field 属性的对象类型
常用方法
:
1. get(Object o );
参数
:
要获取属性的对象
获取指定对象的此属性值 2. set(Object o , Object value);
3. getName()
获取属性的名称
4. setAccessible(boolean flag)
如果
flag
为
true
则表示忽略访问权限检查
!(
可以访问任何权限的属性
)
3.8、获取注解信息
3.8.1、获取类/属性/方法的全部注解对象
Annotation[] annotations01 = Class/Field/Method.getAnnotations();
for (Annotation annotation : annotations01) {
System.out.println(annotation);
}
3.8.2、根据类型获取类/属性/方法的注解对象
注解类型 对象名
= (
注解类型
) c.getAnnotation(
注解类型
.class);
4、内省
4.1、简介
基于反射
, java
所提供的一套应用到
JavaBean
的
API
一个定义在包中的类
,
拥有无参构造器
所有属性私有
,
所有属性提供
get/set
方法
实现了序列化接口
这种类
,
我们称其为
bean
类
.
Java
提供了一套
java.beans
包的
api ,
对于反射的操作
,
进行了封装
!
4.2、Introspector
获取
Bean
类信息
方法
:
BeanInfo getBeanInfo(Class cls)
通过传入的类信息
,
得到这个
Bean
类的封装对象
.
4.3、BeanInfo
常用的方法
:
MethodDescriptor[] getPropertyDescriptors():
获取
bean
类的
get/set
方法 数组
4.4、MethodDescriptor
常用方法
:
1. Method getReadMethod();
获取一个
get
方法
2. Method getWriteMethod();
获取一个
set
方法
有可能返回
null
注意
,
加判断
!