一:eclipse及IDE开发工具介绍:
perspective : 透视图
java Comiler:java编译器
Window-->Preferences-->General-->Keys-->
1: Workspace与project
一个工作间包含多个工程.
如果在Workspace中配置eclipse会影响Workspace中的每一个project.
2:设置单个工程的javac与java
高版本的java能运行低版本的javac编译的程序.
低版本的java不能运行高版本的javac编译的程序.
3模版代码
window--Preference--java--Editer--Templates
4:导入库
当导入一个工程时,如果安装目录不一样,可以把工程原有的库删除,添加自己的库.
选中已导入的工程右键--Build Path--Configure Build Path--Libraries--add Library/Remove
在库中添加JRE包:在上述过程后--add Libraries--JRE System Library--User Libraries--New(新建库)--Add JRE(添加JRE包)
可以把很多要用到的JRE添加到库中.
二:
1:静态导入:1.5版本以后.
(1)import语句可以导入一个类或某个包中的所有类.
(2)import static 语句可以导入一个类中的某个静态方法或所有静态方法.
例:import static java.lang.Math.*;
2:可变参数:一个方法接收参数不固定.
格式: 返回值类型 方法名(数据类型... 数组名){}
注意:假如有多个参数的时候,而且你的参数有可变参数,这个时候,可变参数必须置于方法参数的最后边.
例: int run(int b,int...a){}
特点:
(1)只能出现在参数列表的最后;
(2)...位于变量类型和变量名之间,前后有无空格都可以.
(3)调用可变参数的方法时,编译器为该可变参数隐含创建一个数组,在方法体中以数组的形式访问可变参数.
例:
public class static_import {
public static void main(String[] args){
System.out.println(show(2,3));
System.out.println(show(3,4,5,7));
}
public static int show(int x,int...args){
int sum=x;
for(int i=0;i<args.length;i++){
sum+=args[i];
}
return sum;
}
}
3:增强for循环
格式:
for(元素的数据类型 变量名:数组或Collection集合)
{
执行语句;
}
好处:
简化了对数组,集合的遍历.
注意事项:
迭代变量必须在()中定义.
集合变量可以是数组或实现了Iterator接口的集合类.
例:for(int arg:args){
System.out.println(arg);//自动从数组arr中的0索引出开始,获取每一个值赋给x.
}
4:基本数据类型的自动装箱与拆箱
自动装箱:
Integer num = 12; //把基本数据类型装成Integer对象类型.
自动拆箱:
System.out.println(num+12); //12是基本数据类型,num是Integer对象类型,会自动把Integer类型拆成int类型的.
自动装箱采用的是享元模式:
基本数据类型装箱成对象类型会把(byte)-128-127之间的数存放在缓冲中,如果在装箱的时候会先去缓冲中去
找有没有这样的数,如果有就不创建新的对象. 如果没有才会创建.
Integer m=12;
Integer n=12;
System.out.println(m==n); //true
Integer m=128;
Integer n=128;
System.out.println(m==n); //false
5:享元模式(flyweight):自动装箱就是采用享元模式.
很多小的对象,有很多相同的东西那就他们变成一个对象,
哪些不同的对象,把他们变成方法的参数进行传递.
三:枚举:Enum
1:为什么要有枚举:
枚举就是要让某个类型的变量的取值只能为若干个固定值中的一个,否则,编译器就会报错.
枚举可以让编译器在编译时就可以控制源程序中填写的非法值,普通变量的方式在开发阶段无法实现这一目标.
如果想在一个类中编写完各个枚举类和测试调用类,那么可以将枚举类定义成调用类的内部类.
2:用普通类定义一个Weekday的类来模拟枚举功能.
分析:
私有的构造方法
每个元素分别用一个公有的静态成员变量表示.
可以有若干公有方法或抽象方法, 例如,要提供nextDay方法必须是抽象的.
采用抽象方法定义nextDay就将大量的if.else语句转移成了一个个独立的类.
public class EnumDemo {
public static void main(String[] args){
//SUN和MON是Weekday的常量对象(此常量是对象)
Weekday weekday1 = Weekday.SUN; //把SUN赋给weekday1
Weekday weekday2 = Weekday.MON; //把MON赋给weekday2
System.out.println(weekday1.nextDay());
System.out.println(weekday2.nextDay());
}
}
abstract class Weekday{
private Weekday(){};
abstract Weekday nextDay();
//使用内部类的好处:将一个个if.else语句转移成一个个独立的类.
//在此处SUN是常量,此常量属于对象.
public final static Weekday SUN = new Weekday(){ //使用内部类,并在内部类中覆写抽象方法.
public Weekday nextDay(){
return MON;
}
};
public final static Weekday MON = new Weekday(){ //使用内部类,并在内部类中覆写抽象方法.
public Weekday nextDay(){
return SUN;
}
};
/*public Weekday nextDay(){
if(this==SUN){
return MON;
}else{
return SUN;
}
}*/
public String toString(){ //覆写toString方法
return this==SUN?"Sun":"MON";
}
}
3: 枚举 枚举的元素都是一个个的对象.
格式:
权限修饰符 enum 类名{}
构造方法:
protected Enum(String name, int ordinal) 单独的构造方法。
常用方法:
public class EnumDemo1 {
public static void main(String[] args){
WeekDays weekDay1 = WeekDays.MON;
System.out.println(weekDay1.nextDay());
WeekDays weekDay2 = WeekDays.FRI;
System.out.println(weekDay2);
System.out.println(weekDay2.name()); //返回此枚举常量的名称,在其枚举声明中对其进行声明。
System.out.println(weekDay2.ordinal()); //返回枚举常量的序数(它在枚举声明中的位置,其中初始常量序数为零)。
System.out.println(WeekDays.valueOf("SUN").toString()); //返回带指定名称的指定枚举类型的枚举常量。
System.out.println(WeekDays.values().length); //返回枚举元素的长度.
}
}
enum WeekDays{
SUN,MON,TUE,WED,THI,FRI,SAT ;
public Enum nextDay() {
// TODO Auto-generated method stub
return TUE;
}
}
4:带有抽象方法的枚举
枚举只有一个成员时,就可以作为一种单例的实现方式.
enum TrafficLamp{
//RED,GREEN,YEELLOW;
RED(30){ //使用内部类的方法覆写抽象方法
public TrafficLamp nextLamp(){
return GREEN;
}
},
GREEN(45){
public TrafficLamp nextLamp(){
return RED;
}
},
YELLOW(5){
public TrafficLamp nextLamp(){
return RED;
}
};
public abstract TrafficLamp nextLamp();
private int time; //交通灯亮的时间
private TrafficLamp(int time){ //带参构造方法
this.time=time;
}
}
四:反射 , 不是1.5的新特性,是java1.2就有
反射会导致程序性能严重下降.
字节码的比较用== ,因为是同一份字节码.
1:反射的基石---->Class类
java类用于描述一类事物的共性,该类事物有什么属性,没有什么属性,置于这个属性的值是什么,
则是由这个类的实例对象类确定的.不同的实例对象有不同的属性值,java程序中的各个java类,他
们是属于同一类事物,可以用一个类来描述着个类事物,这个类的名字就是Class.
Class类描述了类的名字,类的访问属性,类所属于的包名,字段名称的列表,方法名称的列表,等等.
每一个字节码文件(即 .class文件)都是一个Class类的对象.
2:获取类的字节码文件描述的类的方式:
第一种:对象.getClass();
Person p=new Person();
Class c=p.getClass(); //取得字节码文件.
第二种:类名.class
Class c2=Person.class; //取得字节码文件.
第三种:Class.forName("类名") (较为常用)
Class c3=Class.forName("cn.pojo.Person"); //类的完整名称
前两种和第三种的区别:
前两种必须明确Person的类型.
面试题:Class.forName的作用:
(1):字节码文件已经被加载到虚拟机中,则直接返回此字节码文件
(2):字节码文件没有还没有被加载到虚拟机中,则使用类加载器去加载,
把字节码文件加载到虚拟机中,并返还字节码文件.
例:
public class GetClassDemo {
public static void main(String[] args)throws Exception{
String str="asdf";
Class cla1=str.getClass(); //通过对象名.getClass()取得字节码文件
Class cla2=String.class; //通过类名.class取得字节码文件
Class cla3=Class.forName("java.lang.String");
System.out.println(cla1==cla2);
System.out.println(cla2==cla3);
}
}
3: 有九种预定义的 Class 对象,表示八个基本类型和 void。这些类对象由 Java 虚拟机创建,与其表示的基本类型同名,即 boolean、byte、char、short、int、long、float 和 double。
八种基本数据类型的Class字节码文件:基本数据类型.Class
通过包装类得到基本数据类型的字节码文件:如 ,Class cla=包装类.TYPE;
例:int.Class==Integer.TYPE;
4: boolean isPrimitive()
判定指定的 Class 对象是否表示一个基本类型。
5: boolean isArray()
判定此 Class 对象是否表示一个数组类。
总之,只要是在源程序中出现的类型,都有各自的Class实例对象,例如:int,void,...
6:反射就是把java类中的各种成分映射成相应的java类.例如,一个java类中用一个
Class类的对象来表示,一个类中的组成部分:成员变量,方法,构造方法,包等等信息也用一个个的
java类来表示,表示java类的Class类显然要提供一系列的方法,来获得其中的变量,方法,构造,修饰符,包等信息,
这些信息就是用相应的实例对象来表示.它们是Field,Method,Contructor,Package等等.
一个类中的每个成员都可以用相应的反射API类的一个实例对象来表示,
通过调用Class类的方法可以得到这些实例对象后,有什么用?怎么用呢?????????????????????????
首先得到各个成分多对应的对象,利用这些对象做一些事情.
7:常用方法;
Method getMethod(String name, Class<?>... parameterTypes)
返回一个 Method 对象,它反映此 Class 对象所表示的类或接口的指定公共成员方法。
每一个Method对象都是对应着一个实实在在的方法.
第一个参数是方法的名字.第二个参数是该方法的参数的字节码文件.
Method[] getMethods()
返回一个包含某些 Method 对象的数组,这些对象反映此 Class 对象所表示的类或接口(包括那些由该类或接口声明的以及从超类和超接口继承的那些的类或接口)的公共 member 方法。
Field getField(String name)
返回一个 Field 对象,它反映此 Class 对象所表示的类或接口的指定公共成员字段。
String getName()
以 String 的形式返回此 Class 对象所表示的实体(类、接口、数组类、基本类型或 void)名称。
Package getPackage()
获取此类的包。
T newInstance()
创建此 Class 对象所表示的类的一个新实例。
Class<?>[] getInterfaces()
确定此对象所表示的类或接口实现的接口。
Class<T> getDeclaringClass()
返回 Class 对象,该对象表示声明由此 Constructor 对象表示的构造方法的类。
int getModifiers()
以整数形式返回此 Constructor 对象所表示构造方法的 Java 语言修饰符。
8:Construction类
(1)Constructor<?>[] getConstructors()
得到某个类所有的公共构造方法
例:Constructor[] con = Class.forName("java.lang.String").getConstructors();
(2)Constructor<T> getConstructor(Class<?>... parameterTypes)
得到某一个构造方法,Constructor的参数中封装了可变参数列表,所以可以接收任何参数和个数的参数.
例;Constructor con = Class.forName("java.lang.String").getConstructor(StringBuffer );
Constructor con=String.forName("java.lang.String").getConstructor(new StringBuffer("ghjkl"));
//获得方法时要用到类型.
(3)创建实例对象;
通常方式:String str = new String(new StringBuffer("asd"));
反射方式:String str = (String)con.newInstance(new StringBuffered("asd"));
//调用获得的方法时要用到上面相同类型的实例对象.
使用反射创建一个实例对象的步骤是:
获得Class文件
通过class文件进行操作(获得成员,方法等操作).
9:Class.newInstance()方法
T newInstance(Object... initargs)
使用此 Constructor 对象表示的构造方法来创建该构造方法的声明类的新实例,
并用指定的初始化参数初始化该实例。
例:String obj = (String)Class.forName("java.lang.String").newInstance();
该方法内部先得到默认的构造方法,然后用该构造方法创建实例对象.
该方法内部的具体代码是怎么样写的呢? 用到了缓存机制来保存默认构造方法的实例对象.
10:Field类(成员变量)
(1)File类代表某个类中的一个成员变量
Object get(Object obj)
返回指定对象上此 Field 表示的字段的值。
Field getField(String name)
返回一个 Field 对象,它反映此 Class 对象所表示的类或接口的指定公共成员字段。
Field[] getFields()
返回一个包含某些 Field 对象的数组,这些对象反映此 Class 对象所表示的类或接口的所有可访问
公共字段。
Class<?> getType()
返回一个 Class 对象,它标识了此 Field 对象所表示字段的声明类型。
Filed getDeclaredField(String name)
返回一个私有Field对象,它反映此Class对象所表示的类或接口的指定私有成员字段.
Field setAccessible(boolean bo);
如果bo为true表示额可以访问私有属性(暴力反射),如果bo为false表示不能访问私有属性.
例;
class Reflect{
private int x;
public int y;
String str1="string";
String str2="astringent";
String str3="werty";
public Reflect(int x,int y){
this.x=x;
this.y=y;
}
}
public class ReflectDemo{
public static void main(String[] args){
Reflect pt1 = new Reflec(3,5);
Field fileY = pt1.getClass().getField("y"); //获得属性对象.
//fielY 不是对象上的变量,而是类上的,要用它得到对象的变量值.
System.out.println(fileY.get(pt1)); //运行结果是: 5
Field fielX = pt1.getClass().getDeclaredField("x"); //获得私有属性的对象.
fielX.setAccessible(true); //设置为可以访问.
System.out.println(fieldX.get(pt1)); //运行结果是: 3
}
public static void changeString(Object obj)throws Exception{
Field[] fields = obj.getClass().getFields(); //得到所有的属性对象
for(Field field:fields){
if(field.getType()==String.class()){ //判断是不是String字节码文件对象.
String oldValue = (String)field.get(obj);
String newValue = oldValue.replace('b','a');
field.set(obj,newValue);
}
}
}
}
***
11:Method类,代表某个类中的一个成员方法.
Method getMethod(String name, Class<?>... parameterTypes)
返回一个 Method 对象,它反映此 Class 对象所表示的类或接口的指定公共成员方法。
每一个Method对象都是对应着一个实实在在的方法.
第一个参数是方法的名字.第二个参数是该方法的参数的字节码文件.
Method[] getMethods()
返回一个包含某些 Method 对象的数组,这些对象反映此 Class 对象所表示的类或接口(包括那些由该类或接口声明的以及从超类和超接口继承的那些的类或接口)的公共 member 方法。
例:使用反射如何得到并调用String类中的charAt方法
String str = "abc";
//第一个参数是要得到方法名字,即,charAt.第二个参数是charAt(int index)的参数的字节码文件
Method methodCharAt = String.class.getMethod("charAt",int.class); //取得charAt方法对象.
//invoke是调用charAt的功能.,第一个参数是调用者,第二个参数是方法的参数
//在此处str是要调用charAt方法的对象,1是charAt方法中的参数.而methodCharAt是charAt方法的一个对象,是被调用者.
methodCharAt.invoke(str,1); //调用charAt方法
如果传递给Method对象的invoke()方法的第一个参数为null,这说明该Method对象对应的是一个静态方法.
完整例子:
class Demo
{
public static void main(String args[]) throws SecurityException, NoSuchMethodException, IllegalArgumentException, IllegalAccessException, InvocationTargetException {
String str = "abc";
Method getMethod = String.class.getMethod("charAt", int.class);
System.out.println(getMethod.invoke(str, 2)); //运行结果是c
System.out.println(getMethod.invoke(str, 1)); //运行结果是b
}
}
13:
目标:用反射方式执行某个类中的main方法.
问题:
启动Java程序的main方法的参数是一个字符串数组,即public static void main(String[] args),
通过反射方式来调用这个main方法时,如何为invoke方法传递参数呢?按jdk1.5的语法,整个数
组是一个参数,而按jdk1.4的语法,数组中的每个元素对应一个参数,当把一个字符串数组作
为参数传递给invoke方法时,javac会到底按照哪种语法进行处理呢?jdk1.5肯定要兼容jdk1.4的
语法,会按jdk1.4的语法进行处理,即把数组打散成为若干个单独的参数。所以,在给main方法传
递参数时,不能使用代码mainMethod.invoke(null,new String[]{“xxx”}),javac只把它当作jdk1.4的
语法进行理解,而不把它当作jdk1.5的语法解释,因此会出现参数类型不对的问题。
解决办法:
mainMethod.invoke(null,new Object[]{new String[]{"xxx"}});
mainMethod.invoke(null,(Object)new String[]{"xxx"}); ,编译器会作特殊处理,
编译时不把参数当作数组看待,也就不会数组打散成若干个参数了
14:数组的反射:
(1)具有相同维数和元素类型的数组属于同一个类型,即,具有相同的Class实例对象.
我们只能取到数组元素的getName(),得不到整个数组的getName(),因为Object数组可以接收任意类型.
(2)代表数组的Class实例对象的getSuperclass()方法返回的父类为Object类对应的Class.
(3)基本类型的一维数组可以被单做Object类型使用,不能当做Object[]类型使用; 非基本类型
的一维数组,既可以当做Object类型使用,又可以当做Object[]类型使用.
(4)Array工具类用于完成对象数组的反射操作.
(5)Arrays.asList()方法处理int[] 和 String[]时的差异.
Arrays类中的方法:asList,把数组转换成List对象.
只有引用数据类型对象转换成List对象后能打印出元素.基本数据类型的数组转换后只能打印出内存地址.
例:
class Demo
{
public static void main(String[] args)
{
int[] a1={1,2,32,4};
String[] a2={"sdf","wer","few"};
System.out.println(Arrays.asList(a1));
System.out.println(Arrays.asList(a2));
}
}
运行结果:[[I@5e55ab] 和 [sdf, wer, few]
例:
/*
使用反射打印,如果是数组,则打印数组中的元素.
如果不是数组,则直接打印值.
*/
import java.util.Arrays;
import java.lang.reflect.Array;
class Demo
{
public static void main(String[] args)
{
int[] a1={1,2,32,4};
String[] a2={"sdf","wer","few"};
int a3 = 345;
String a4 = "asdf";
printObject(a2);
printObject(a4);
}
public static void printObject(Object obj){
Class clazz = obj.getClass(); //得到字节码文件对象
if(clazz.isArray()){ //判断是否是数组 ,如果是数组就打印出数组中的元素.
int len = Array.getLength(obj); //得到数组的长度
for(int i=0;i<len;i++){
System.out.println(Array.get(obj,i));//返回指定数组对象中索引组件的值。
}
}else{
System.out.println(obj); //如果不是数组,就直接打印
}
}
}
对象已不再用,但是未被释放.会造成内存泄露.
15:反射的作用--->实现框架功能
例:框架与框架要解决的核心问题
我做房子卖给用户住,由用户自己安装门窗和空调,我做的房子就是框架,,用户需要
使用我的框架,把门窗装进我提供的框架中. 框架与工具类的区别,工具类被用户的
类调用,而框架则是调用用户提供的类.
16:得到资源文件的方式:
(1):getRealPath();//得到一个项目在硬盘上的具体文职.
一定要记住用完整的路径,但完整的路径不是硬编码,而是运算出来的.
(2):类加载器ClassLoader
getClassLoad()得到类加载器.
getResourceAsStream(String name),从class文件所指定的目录中逐一查找要加载的文件.
五:JavaBean
1:
(1)JavaBean是一种特殊的Java类,主要用于传递数据信息,这种java类中的方法主要用于访问私有的字段,
且方法名符合某种命名规范.
(2)如果要在两个模块之间传递多个信息,额可以将这些信息封装到一个JavaBean中,这种JavaBean的实例对象
通常称之为值对象.(Value Object,简称为VO)这些信息在类中用私有字段来存储,如果读取或设置这些字段的值,
则需要通过一些相应的方法来访问,大家觉得这些方法的名称叫什么好呢? JavaBean的属性是根据其中的setter
和getter方法来确定的,而不是根据其中的成员变量.如果方法名为setId,中文意思即为设置id,置于你把它存到哪个
变量上,用管吗?(不用管) 如果方法名为getId,中文意思即为获取id,置于你从哪个变量上取,用管吗?(不用管),
去掉set前缀,剩余部分就是属性名,如果剩余不分的第二个字母是小写的,则把剩余部分的首字母改成小写的.
如:setId()的属性名-->id
isLast()的属性名-->last
setCPU()的属性名是-->CPU
getUPS()的属性名是-->UPS
总之,一个类被当做JavaBean使用时,JavaBean的属性是根据方法名推断的,它根本看不到java类内部的成员变量.
(3)一个符合JavaBean特点的类可以当作普通类一样进行使用,但把它当JavaBean用肯定需要带来一些额外的好处,
我们才会去了解和应用JavaBean!好处如下:
(1)在Java EE开发中,经常要使用到JavaBean。很多环境就要求按JavaBean方式进行操作,
别人都这么用和要求这么做,那你就没什么挑选的余地!
(2)JDK中提供了对JavaBean进行操作的一些API,这套API就称为内省。如果要你自己去通过getX方法来
访问私有的x,怎么做,有一定难度吧?用内省这套api操作JavaBean比用普通类的方式更方便。
/*
PropertyDescripor类描述 Java Bean 通过一对存储器方法导出的一个属性。
Method getReadMethod()
获得应该用于读取属性值的方法。
Method getWriteMethod()
获得应该用于写入属性值的方法。
*/
例:简单应用
import java.lang.reflect.*;
import java.beans.*;
class Demo
{
public static void main(String[] args) throws Exception
{
ReflectPoint pt1 = new ReflectPoint(3,5);
String propertyName = "x";
//取得值.
//第一个参数是属性名,第二个参数是要操作的对象的.
PropertyDescriptor pd = new PropertyDescriptor(propertyName,pt1.getClass());
Method methodGetX = pd.getReadMethod();
//因为getter方法没有参数,所以不用写,只写调用对象就可以了.
Object retVal = methodGetX.invoke(pt1);
System.out.println("获取属性值:"+retVal);
//设置值.
Method methodSetX = pd.getWriteMethod();
methodSetX.invoke(pt1,7);
System.out.println("设置后的值:"+pt1.getX());
}
}
class ReflectPoint
{
private int x;
private int y;
public ReflectPoint(int x,int y){
this.x=x;
this.y=y;
}
public int getX(){
return x;
}
public int getY(){
return y;
}
public void setX(int x){
this.x=x;
}
public void setY(int y){
this.y=y;
}
}
2:BeanUtils工具包
演示用eclipse如何加入jar包,先只是引入beanutils包,等程序运行出错后再引入logging包。
在前面内省例子的基础上,用BeanUtils类先get原来设置好的属性,再将其set为一个新值。
get属性时返回的结果为字符串,set属性时可以接受任意类型的对象,通常使用字符串。
用PropertyUtils类先get原来设置好的属性,再将其set为一个新值。
get属性时返回的结果为该属性本来的类型,set属性时只接受该属性本来的类型。
演示去掉JavaBean(ReflectPoint)的public修饰符时,BeanUtils工具包访问javabean属性时出现的问题。
例:
用struts的迭代标签不能迭代出枚举元素的属性,而用jstl的迭代标签则可以。采用BeanUtils去获取带有抽象方法的枚举类的成员对象的属性时,会出现错误,要自己用内省加暴力反射方式才可以获取。主要原因是枚举类的抽象子类不是public类型的。
public static void main(String[] args) {
// TODO Auto-generated method stub
/*System.out.println(
PropertyUtils.getProperty(Sex.NONE, "title"));*/
Object bean = Sex.NONE;
BeanInfo beanInfo = null;
try {
beanInfo = Introspector.getBeanInfo(bean.getClass());
} catch (Exception e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
PropertyDescriptor[] properties = beanInfo.getPropertyDescriptors();
for(PropertyDescriptor property:properties)
{
if(property.getName().equals("title"))
{
Method method = property.getReadMethod();
method.setAccessible(true);
Object retVal;
try {
retVal = method.invoke(bean, null);
System.out.println(retVal);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
六:注解java.lang.Annotation
注解相当于一种标记,在程序中加了注解就等于为程序打上了某种标记,以后,javac编译器,开发工具和其他
程序可以用反射来了解你的类及各种元素上有无何种标记,有什么标记,就去干相应的事.
标记可以加在包,类,字段,方法,方法的参数以及局部变量上.
1:
(1)@SuppressWarnings()
指示应该在注释元素(以及包含在该注释元素中的所有程序元素)中取消显示指定的编译器警告。
注意,在给定元素中取消显示的警告集是所有包含元素中取消显示的警告的超集
(2)@Deprecated 指示该方法已过时.
(3)@Override:重写
(4)@Retention():指示注释类型的注释要保留多久。如果注释类型声明中不存在 Retention 注释,
则保留策略默认为 RetentionPolicy.CLASS。
例: @Retention(RetentionPolicy.RUNTIME),将此注解一直保留到运行结束.
@Retention元注解,其有三种取值:RetentionPolicy.SOURCE, RetentionPolicy.CLASS, RetentionPolicy.RUNTIME :
分别对应java源文件-->class文件-->内存中的字节码. 默认值是在Class阶段.
(5): @Target元注解:指示注解可以用到哪个成分中.
Target的默认值为任何元素,设置Target等于ElementType.METHOD,原来加在类上的注解就报错了,改用数组方式设置{ElementType.METHOD,ElementType.TYPE}就可以了.
2:定义格式: @interface 类名
例:public @interface AnnotationTest{}
元注解:在注解上加的注解.
3:调用注解
Class类中
boolean isAnnotation()
如果此 Class 对象表示一个注释类型则返回 true。
boolean isAnnotationPresent(Class<? extends Annotation> annotationClass)
如果指定类型的注释存在于此元素上,则返回 true,否则返回 false。
<A extends Annotation> A getAnnotation(Class<A> annotationClass)
如果存在该元素的指定类型的注释,则返回这些注释,否则返回 null。
Annotation[] getAnnotations()
返回此元素上存在的所有注释。
4:为注解增加基本属性
(1)什么是注解的属性
一个注解相当于一个胸牌,如果你胸前贴了胸牌,就是传智播客的学生,
否则,就不是。如果还想区分出是传智播客哪个班的学生,这时候可以为
胸牌在增加一个属性来进行区分。加了属性的标记效果为:@MyAnnotation(color="red")
(2)定义基本类型的属性和应用属性:
在注解类中增加String color();
@MyAnnotation(color="red")
(3)用反射方式获得注解对应的实例对象后,再通过该对象调用属性对应的方法
MyAnnotation a = (MyAnnotation)AnnotationTest.class.getAnnotation(MyAnnotation.class);
System.out.println(a.color());
可以认为上面这个@MyAnnotation是MyAnnotaion类的一个实例对象
(4)为属性指定缺省值(默认值):
String color() default "yellow"; 指定默认值为yellow
(5)value属性:
String value() default "zxx";
如果注解中有一个名称为value的属性,且你只想设置value属性(即其他属性都采用默认值
或者你只有一个value属性),那么可以省略value=部分,例如:@MyAnnotation("lhm")。
5:为注解增加高级属性
枚举属性可以是一下几种类型:
八种基本类型,String类型,Class类型,数组类型,枚举类型,注解类型.
(1)数组类型的属性
int [] arrayAttr() default {1,2,3};
@MyAnnotation(arrayAttr={2,3,4})
如果数组属性中只有一个元素,这时候属性值部分可以省略大括
(2)枚举类型的属性
EnumTest.TrafficLamp lamp() ;
@MyAnnotation(lamp=EnumTest.TrafficLamp.GREEN)
(3)注解类型的属性:
MetaAnnotation annotationAttr() default @MetaAnnotation("xxxx");
@MyAnnotation( annotationAttr = @MetaAnnotation (“yyy”) )
可以认为上面这个@MyAnnotation是MyAnnotaion类的一个实例对象,同样的道理,
可以认为上面这个@MetaAnnotation是MetaAnnotation类的一个实例对象,调用代码如下:
MetaAnnotation ma = myAnnotation.annotationAttr();
System.out.println(ma.value());
(4)注解的详细语法可以通过看java语言规范了解,即看java的language specification
(5)枚举和注解都是特殊的类,不能用new 创建它们的实例对象,创建枚举的实例对象就是在其中增加元素。
在程序中如何创建出一个注解的实例对象啊?直接用@放上一个标记即可
MetaAnnotation注解的定义:
public @interface MetaAnnotation {
String value();
}