---------------------- android培训、java培训、期待与您交流! ----------------------
一、eclipse的使用技巧
1:修改快捷键
通常eclipse中有一些快捷键会和别的软件的一些功能快捷设置冲突(例:万恶的QQ),而你又不想更改其他软件设置的话,你就可一将eclipse的快捷键更改.
window - preferences - general - keys
打开keys后在上边会有一个文本框,你可以输入你要更改的功能名称,或快捷方式,底下就会为你列出相应的功能与快捷方式,点击在下面就会出现该功能与功能还有快捷方式了,在Binding上你就可以更改了,但要确定更改后的快捷方式没被其他功能占用
2:更改代码显示大小
window->preferences->general->apperance->colors and fonts->basic->text font
eclipse中的默认代码显示都会很小,特别是中文,你如果也这样觉得的话,可以用这个功能更改
3:设置编辑窗口背景色
window->preferences->general->Editors->Text Editors
右下窗口选Backgroud color,右边点掉System Default按钮,点Color右边的颜色框,选择颜色就ok了
4:修改格式化每行的长度
window->preferences->java->code style->formatter->edit->line wrapping->maximum line width
然后就可以随心所欲调节格式化后每行的长度了
preferences这个菜单下据说有很多功能,大家有时间的话可以试一下
二:常用功能
1:鼠标右键->Source->Comment
注释功能,也可以用"Ctrl+/"快捷键来实现
2:鼠标右键->Source->Organize Import
可以添加没有添加的import,也可以将多余的import删除
可以用"Ctrl+Shift+O"来实现
3:鼠标右键->Source->Override/Implement Method
可以自动搜索父类或接口的方法
4:鼠标右键->Source->Generate Getter and Setter
可以自动为变量写get,set
5:鼠标右键->Source->surround with try/catch block
自动try/catch异常
6:alt + shift + r
将类中的用到的某个变量集体改名
7:ctrl + shift + f
为代码格式化,看起来会更美观
8:alt + shift + m
将写好的某段代码抽取成独立的方法
9:alt + up 或 alt + down
蒋某行代码上移或下移,alt + down可能会和win7的屏幕转换的快捷键冲突
10:ctrl + alt + down
复制某行
11:
单行注释: ctrl + /
多行注释: ctrl + shift + / 或 ctrl + shift + \
12:alt+/
这个就是传说中的强大功能,它就是用来补全代码的,你没写全的,它可以找出好多让你挑着来
13:f4
找到你所引用的类或方法的出处
二、静态导入
1、import 语句可以导入一个类或某一个包中的所有类。
2、import static 语句导入某个类中的静态方法或所有的静态方法。
import static java.lang.Math.*;
class StaticImport
{
public static void main(String[] args)
{
int max = max(3,6);
int abs = Math.abs(3-6);
System.out.println(max);
}
}
三、可变参数
可变参数的特点:
1、只能出现在参数列表的左后;
2、...位于变量类型和变量名之间,前后有无空格都可以;
3、调用可变参数的方法时,编译器为该可变参数隐含创建一个数组,在方法体中以数组的形势形式访问可变参数。
package cn.itcast.day1;
public class VariableParameter {
public static void main(String[] args) {
// TODO Auto-generated method stub
System.out.println(add(2,3));
System.out.println(add(1));
System.out.println(add(2, 3, 4));
}
public static int add(int x,int... args){
int sum = x;
for(int i=0;i<args.length;i++){
sum+=args[i];
}
return sum;
}
}
四、增强for循环
1、语法:for(变量类型 变量名:被遍历的集合或数组名){......}
2、注意事项:
迭代变量必须放在()中定义;
集合变量可以是数组或实现了Iterable接口的集合类。
package cn.itcast.day1;
public class VariableParameter {
public static void main(String[] args) {
// TODO Auto-generated method stub
System.out.println(add(2,3));
System.out.println(add(1));
System.out.println(add(2, 3, 4));
}
public static int add(int... args){
int sum = 0;
/*for(int i=0;i<args.length;i++){
sum+=args[i];
}*/
for(int arg:args){//增强for循环
sum+=arg;
}
return sum;
}
}
五、基本数据类型的自动拆箱与装箱
享元设计模式(flyweight):有很多个小的对象,它们有很多属性相同,把这些属性变成一个对象,把不同的属性变成方法的参数,称之为外部状态。那些相同的属性称之为内部状态。
package cn.itcast.day1;
public class AutoBox {
public static void main(String[] args) {
// TODO Auto-generated method stub
Integer obj = 3;//装箱
System.out.println(obj + 3);//拆箱
Integer i1=5;
Integer i2=5;
//在-128到127之间 时,同一个整数对应的Integer对象相同。
System.out.println(i1==i2);
Integer i3= 138;
Integer i4=138;
System.out.println(i3==i4);
}
}
六、枚举
1、枚举就是要让某个类型的变量的取值只能为若干个固定值中的一个,否则,编译器就会报错。枚举可以让编译器在编译时就可以控制源程序中填写的非法值,普通变量的方式在开发阶段无法实现这一目标
2、用普通类演示如何实现枚举功能,
事例:定义一个Weekday的类来模拟枚举的功能。
package cn.itcast.day1;
public class EnumTest {
public static void main(String[] args) {
// TODO Auto-generated method stub
Weekday weekday = Weekday.SUN;
System.out.println(weekday.nextDay());
}
}
package cn.itcast.day1;
//用普通类模拟枚举,
public abstract class Weekday {
private Weekday(){
}
//用内部类创建抽象类的子类对象
public final static Weekday SUN = new Weekday(){
public Weekday nextDay(){
return MON;
}
};
public static final Weekday MON = new Weekday(){
public Weekday nextDay(){
return SUN;
}
};
//用抽象方法实现nextDay方法
public abstract Weekday nextDay();
//枚举类里的方法
/* public Weekday nextDay(){
if(this==SUN){
return MON;
}
else{
return SUN;
}
}*/
//要打印枚举对象,要怎么打印,有自己定义,覆盖toString方法
public String toString(){
return this==SUN?"SUN":"MON";
}
}
技巧:采用抽象方法定义nextDay()方法,就将大量的if else语句装成了一个独立的类。
从用普通类来实现枚举可以看出,枚举就是一个特殊的类,这个类中的构造方法是私有的的,并且该类的对象和个数已经在内部定义好了。外部只能使用定义好的对象。这个所谓的对象就是枚举中元素。
3、基本枚举类的演示
package cn.itcast.day1;
public class EnumTest {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
Weekday1 weekday = Weekday1.SUN;
System.out.println(weekday.nextDay());
WeekDay weekday2=WeekDay.FRI;
// 枚举中的常用方法介绍:1.打印枚举对象
System.out.println(weekday2);
//获取该枚举的名字
System.out.println(weekday2.name());
//获取枚举元素在枚举中的位置
System.out.println(weekday2.ordinal());
//枚举类中的静态方法,把一个字符串转换成枚举
System.out.println(WeekDay.valueOf("SUN").toString());
//把枚举中的成员装进数组中,可以进行遍历
System.out.println(WeekDay.values().length);
}
//基本枚举的定义方法,记住枚举就是一个特殊的类
public enum WeekDay{
//枚举中的元素列表只能放在枚举中的第一行,如果列表之后还有成员,那么列表最后必须用分号隔开
//在枚举元素的后边跟上一对括号,就表示使用哪个构造方法
SUN(1),MON,TUE,WED,THI,FRI,SAT;
//在枚举中定义构造函数,构造函数只能是private修饰,其他的都不行
private WeekDay(){System.out.println("first");}
private WeekDay(int x){
System.out.println("second");
}
}
}
4、实现带有抽象方法的枚举
//带有抽象 方法的枚举实例:交通灯
//枚举就是一个内部类
public enum TrafficLamp
{
//枚举元素列表后有成员时(成员方法和成员变量),列表后必须用分号,且要写在第一行
RED(30)
{
public TrafficLamp nextLamp()
{
return GREEN;
}
},
GREEN(45)
{
public TrafficLamp nextLamp()
{
return YELLOW;
}
},
YELLOW(5)
{
public TrafficLamp nextLamp()
{
return RED;
}
};
public abstract TrafficLamp nextLamp();//枚举中的抽象方法
private int time;
private TrafficLamp(int time)//枚举中的构造函数
{
this.time=time;
}
}
}
技巧:枚举只有一个成员时,就可以作为一种单例的实现方式。也就这给类只能创建一个对象,枚举中的这个元素就是这个仅有的对象。而不用在new对象了。
七、反射的基石----Class类
1、Java类用于描述这一类事物的共性,描述该类事物有什么属性,不该有什么属性,至于这个属性值是什么,则是由这个类的实例对象来确定的,不同的实例对象有不同的属性值。
2、Java程序中的各个Java类属于同一类事物,描述这类事物的类就是Class类。
3、Class类的实例对象就是内存中一份字节码(Java类的二进制编码)。
4、获取Class类的实例(对象)方式:
a.通过已有类的类名来获取该类的Class对象:Class cls= Person.class;
b.通过已有类的对象名来获取该对象所属类的Class对象:
Person p1 = new Person(); Class cls2 = p1.getClass();
c.通过Class类中的一个静态方法Class.forName("内的名字"),
例如:Class cls3=Class.forName("Person");
用这种方法获取类的字节码对象有两种方式:
第一种:如果要获取字节码的类已经加载在内存中了,就直接获取,不用再加载了。
第二种:如果要获取字节码的类还没有加载在内存中,就先用类加载器将该类加载进内 存缓存起来,在返回该类的字节码。
8、九个预定义Class实例对象
8个基本数据类型和一个void。
package cn.itcast.day1;
public class ReflectTest {
public static void main(String[] args) throws Exception{
// TODO Auto-generated method stub
String str1 = "abc";
Class cls1 = String.class;
Class cls2 = str1.getClass();
Class cls3 = Class.forName("java.lang.String");
//一个类字节码只有一个
System.out.println(cls1==cls2);
System.out.println(cls1==cls3);
//判断String类的字节码是不是基本类型
System.out.println(cls1.isPrimitive());//false,String不是基本类型
//判断int的字节码是不是基本类型
System.out.println(int.class.isPrimitive());
//int的字节码和Integer的字节码是不一样的
System.out.println(int.class==Integer.class);//false
//int的字节码和被Integer所包装的类型的字节码是一样的
System.out.println(int.class==Integer.TYPE);//true
//数组的字节码不是基本类型(原始类型)
System.out.println(int[].class.isPrimitive());//false
//判断一个字节码是不是数组呢
System.out.println(int[].class.isArray());//true
}
}
总之,只要在源程序中出现的类型,都有各自的Class实例对象。例如:int[],void
七、反射
反射就是把Java类中的各中成分映射成相应的Java类。一个类中的每个成员都可以用相应的的反射API类的一个实例对象来表示。通过调用Class类的方法可以得到这些实例对象。
(一)Constructor类(构造函数的反射)
代表Java类中的构造方法。
1、得到某个类所有的构造方法:Constructor[] getConstructors();
2、得到某一个构造方法:Constructor getConstructor();通过参数的类型来区别要得到的是哪个构造方法。
package cn.itcast.day1;
import java.lang.reflect.Constructor;
public class ReflectTest {
public static void main(String[] args) throws Exception{
//用反射的方法创建String类的对象,使用带StringBuffer()参数的构造方法
//1.通过String类的字节码对象,获取其带StringBuffer()参数的构造函数
Constructor constructor1=
String.class.getConstructor(StringBuffer.class);
//2.用这个构造方法创建对象
String str2 =(String)constructor1.newInstance(new StringBuffer("abc"));
System.out.println(str2.charAt(2));
}
}
3、Class.newInstance()方法:直接调用无参的构造函数,创建这个类的实例。
(二)Field类(成员变量的反射)
Field类代表Java类中的成员变量。
1.获取费私有成员变量的方法: Field getField();只能返回类中非私有的成员变量。类中私有的成员变量对这个方法是不可见的。
2.获取私有成员变量的方法:Field getDeclareField();
3.要想取得私有成员在某个对象中的取值,还要把这个私有成员设置成可得到的:方法是setAccessible(true);
package cn.itcast.day1;
public class ReflectPoint {
private int x;
public int y;
public ReflectPoint(int x, int y) {
super();
this.x = x;
this.y = y;
}
}
package cn.itcast.day1;
import java.lang.reflect.Field;
public class ReflectTest1 {
public static void main(String[] args) throws SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException {
// TODO Auto-generated method stub
ReflectPoint pt1 = new ReflectPoint(3,5);
//获取非私有的成员变量y的字节码对象
Field fieldy = pt1.getClass().getField("y");
//获取该成员变量在某个特定实例中的值,注意fieldy不是某个类身上的成员变量,而是类的成员变量
System.out.println(fieldy.get(pt1));
//获取私有成员变量x的字节对象
Field fieldx = pt1.getClass().getDeclaredField("x");
//获取私有成员变量在特定对象中的值,要先把私有成员变成可得到的后才能取值
fieldx.setAccessible(true);
System.out.println(fieldx.get(pt1));
}
}
(三)Method类
代表Java类中的成员方法类。获取该类对象的方法是:Method getMethod();
package cn.itcast.day1;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
public class ReflectTest {
public static void main(String[] args) throws Exception{
String str1 = "abc";
//获取String类的charAt(int)方法
Method methodCharAt = String.class.getMethod("charAt",int.class);
//在某个对象上使用这个方法
System.out.println(methodCharAt.invoke(str1, 2));
//注意:invoke(null,orgs)这时所使用的是静态方法,没有对象。
}
}
事例:用反射的方式执行某个类中的main方法:被调用的类是在运行的时候传进去的。
package cn.itcast.day1;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
public class ReflectTest {
public static void main(String[] args) throws Exception{
//用反射的方式执行某个类中的main方法
String startClassName = args[0];
Method mainMethod = Class.forName(startClassName).getMethod("main",String[].class );
//使用这个main方法
// mainMethod.invoke(null,new Object[]{new String[]{"aaa","bbb","vvv"}});//在这儿要把参数再封装一下
//第二种封装的方法
mainMethod.invoke(null, (Object)new String[]{"aaa","bbb","vvv"});
}
}
class TextArguments
{
public static void main(String[] args)
{
for(String arg:args)
{
System.out.println(arg);
}
}
}
(四)数组的反射类--Array类
1.具有相同维数和相通元素类型的数组属于同一个类型,即具有相同的Class实例对象。
package cn.itcast.day1;
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
public class ReflectTest {
int[] a1= new int[]{1,2,3};
String[] a2 = new String[]{"eage","erge","ergeg"};
printObject(a1);
printObject("dfseg");
}
private static void printObject(Object obj) {
// TODO Auto-generated method stub
Class objClass = obj.getClass();
if(objClass.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);
}
}
}
八、框架的概念及用反射技术开发框架的原理
简单的说框架就是已经写好了的程序如何调用还没有写的类。
1.建立配置文件
2.在要用到的程序读取配置文件
package cn.itcast.day1;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.Collection;
import java.util.HashSet;
import java.util.Properties;
public class ReflectTest2 {
/**
* @param args
*/
public static void main(String[] args)throws Exception {
// TODO Auto-generated method stub
//读取配置文件建立文件读取流对象
InputStream is = new FileInputStream("config.properties");
Properties prop = new Properties();
prop.load(is);
is.close();
//Collection collection = new HashSet();
//反射在框架下的应用,一定记住用完整的路径,这个绝对路径是运算出来的
Collection collection =
(Collection)Class.forName(prop.getProperty("className")).newInstance();
ReflectPoint pt1 = new ReflectPoint(3,3);
ReflectPoint pt2 = new ReflectPoint(4,4);
ReflectPoint pt3 = new ReflectPoint(5,5);
collection.add(pt1);
collection.add(pt2);
collection.add(pt3);
collection.add(pt1);
System.out.println(collection.size());
}
}
九、用类加载器的方式管理资源和配置文件
package cn.itcast.day1;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.Collection;
import java.util.HashSet;
import java.util.Properties;
public class ReflectTest2 {
/**
* @param args
*/
public static void main(String[] args)throws Exception {
// TODO Auto-generated method stub
//读取配置文件建立文件读取流对象
InputStream is = new FileInputStream("config.properties");
Properties prop = new Properties();
prop.load(is);
is.close();
// Collection collection = new HashSet();
//反射在框架下的应用,一定记住用完整的路径,这个绝对路径是运算出来的
Collection collection =
(Collection)Class.forName(prop.getProperty("className")).newInstance();
//用类加载器来加载配置文件的演示
//Collection collection=
ReflectTest2.class.getClassLoader().getResourceAsStream(cn/itcast/day1/config.properties);
//用类直接加载文件
//ReflectTest2.class.getResourceAsStream("config.properties");
ReflectPoint pt1 = new ReflectPoint(3,3);
ReflectPoint pt2 = new ReflectPoint(4,4);
ReflectPoint pt3 = new ReflectPoint(5,5);
collection.add(pt1);
collection.add(pt2);
collection.add(pt3);
collection.add(pt1);
System.out.println(collection.size());
}
}
十、内省-----了解JavaBean
(一)JavaBean是一种特殊的Java类,主要用于传递数据信息,这种java类中的方法主要用于访问私有的字段,且方法名符合某种命名规则。方法名都是以set和get开头。
(二)对JavaBean的简单的内省操作:用到一个API 是PropertyDescriptor
package cn.itcast.day1;
import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class IntroSpecterTest {
public static void main(String[] args)throws Exception {
// TODO Auto-generated method stub
ReflectPoint pt1 = new ReflectPoint(3,5);
//JavaBean的内省操作,获取x属性的值
//System.out.println(pt1.getX());
String propertyName = "x";
//获取对类中x属性描述的对象
Object retVal = getProperty(pt1, propertyName);
System.out.println(retVal);
//用内省的方法设置x属性的值,想要设置给个属性的值,就必须先得到这个属性对象
Integer value = 7;
//PropertyDescriptor pd1 =
new PropertyDescriptor("x",pt1.getClass());
//Method methodSetX=pd1.getWriteMethod();
//methodSetX.invoke(pt1, value);
setProperty(pt1,propertyName,value);
System.out.println(pt1.getX());
}
private static Object getProperty(Object pt1, String propertyName)
throws IntrospectionException, IllegalAccessException,
InvocationTargetException {
PropertyDescriptor pd =
new PropertyDescriptor(propertyName,pt1.getClass());
//通过这个属性对象获取读取该属性的方法
Method methodGetX =pd.getReadMethod();
//通过返回属性x的值得方法来获取pt1对象中的x的值
Object retVal = methodGetX.invoke(pt1);
return retVal;
}
private static void setProperty(Object pt,String propertyName,Object value)throws Exception{
PropertyDescriptor pd2=
new PropertyDescriptor(propertyName,pt.getClass());
Method methodSetX = pd2.getWriteMethod();
methodSetX.invoke(pt, value);
}
}
(三)对JavaBean的复杂内省操作----introSpecttor类
采用遍历BeanInfo的所有属性的方式来查找和设置某个ReflectPoint对象的X属性。在程序中把一个类当做JavaBean来看,就是调用IntroSpector.getBeanInfo方法,得到的BeanInfo对象封装了把这个类当做JavaBean看的结果信息。
package cn.itcast.day1;
import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class IntroSpecterTest {
public static void main(String[] args)throws Exception {
ReflectPoint pt1 = new ReflectPoint(3,5);
Object retVal = getProperty1(pt1,propertyName);
System.out.println(retVal);
}
private static Object getProperty1(Object pt1,String propertyName)throws Exception{
Object value = null;
BeanInfo beanInfo = Introspector.getBeanInfo(pt1.getClass());
PropertyDescriptor[] pds = beanInfo.getPropertyDescriptors();
for(PropertyDescriptor pd:pds)
{
if(pd.getName().equals(propertyName))
{
Method methodGetX = pd.getReadMethod();
methodGetX.invoke(pt1);
break;
}
}
return value;
}
}
(四)使用BeanUtils工具包操作JavaBean
1.导入BeanUtils的jar包和logging的jar包
//获取属性的值
BeanUtils.getProperty(pt1,"x",);
//设置属性的值
BeanUtils.setProperty(pt1,"x","9")//注意:参数的类型都是字符串
十一、注解
注解是向javac或者开发工具传递某种信息的标记。每一个注解都是一个类。注解相当于一种标记,在程序中加了注解就等于为程序打上了某种标记,javac编译器、开发工具和其他程序可以用反射来了解你的类及各种元素上有无何种标记,有什么样的标记,就去做相应的操作。标记可以加在包,类,字段,方法的参数以及局部变量上。
(一)注解的定义与反射调用
1、基本注解:Deprecated、Override、SuppressWarning
2、注解的生存阶段:java源文件、class文件、内存(运行阶段)。
3、标注注解生存阶段的方法:可以在注解上再添加注解(也叫元注解)并标明被注解的注解存在于那个阶段。@Retention(RetentionPolicy.SOURCE)(注解存在于源 文件),@Retention(RetentionPolicy.CLASS),
@Retention(RetentionPolicy.RUNTIME)
package cn.itcast.day2;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
//让自定义注解生存在运行阶段
@Retention(RetentionPolicy.RUNTIME)
//设置子定义注解的要作用的成分
@Target({ElementType.METHOD,ElementType.TYPE})
public @interface ItcastAnnotation {
}
package cn.itcast.day2;
@ItcastAnnotation
public class AnnotationTest {
/**
* @param args
*/
public static void main(String[] args) throws Exception{
// TODO Auto-generated method stub
//用反射的方法查看标注到该类上的自定义注解是否存在
if(AnnotationTest.class.isAnnotationPresent)(ItcastAnnotation.class))
{
ItcastAnnotation annotation =(ItcastAnnotation)AnnotationTest.class.getAnnotation(ItcastAnnotation.class );
System.out.println(annotation);
}
}
}
(二)为注解增加各种属性
package cn.itcast.day2;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import cn.itcast.day1.EnumTest;
//让自定义注解生存在运行阶段
@Retention(RetentionPolicy.RUNTIME)
//设置子定义注解的要作用的成分
@Target({ElementType.METHOD,ElementType.TYPE})
public @interface ItcastAnnotation {
//为注解添加属性,注解类似于接口,定义属性以方法的形式定义
String color() default "blue";//设置属性的默认值
//value特殊的属性名,如果注解中只有该属性要设置值,则不需要写该属性名称,直接写值即可。
String value();
//为注解增加数组类型的属性,并为数组属性设置默认值
int[] arrayAtrr() default {3,4,5};
//为注解增加枚举属性,并增加默认值
EnumTest.TrafficLamp lamp()default EnumTest.TrafficLamp.RED;
//为注解添加注解类型的属性,并赋默认值
MetaAnnotation annotation1() default @MetaAnnotation("vae");
}
对各种注解属性的初始化实例:
package cn.itcast.day2;
//在使用注解实例时就要为注解中的属性赋值,以及数组属性赋值的方法,在加上为注解类型的属性赋值
@ItcastAnnotation(color="red",value="sfwe",arrayAtrr={1,2,3},annotation1=@MetaAnnotation("ifuh"))
public class AnnotationTest {
/**
* @param args
*/
//只需给value属性赋值时,就不用写属性名value了
@ItcastAnnotation("sfgewg")
public static void main(String[] args) throws Exception{
// TODO Auto-generated method stub
//用反射的方法查看标注到该类上的自定义注解是否存在
if(AnnotationTest.class.isAnnotationPresent(ItcastAnnotation.class)){
ItcastAnnotation annotation =(ItcastAnnotation)AnnotationTest.class.getAnnotation(ItcastAnnotation.class );
//在查看注解属性时,要以方法形式调用
System.out.println(annotation.color());
//查看value属性
System.out.println(annotation.value());
//查看数组属性
System.out.println(annotation.arrayAtrr().length);
//查看枚举属性
System.out.println(annotation.lamp().nextLamp().name());
//查看注解属性
System.out.println(annotation.annotation1().value());
}
}
}
十二、泛型
(一)泛型应用
泛型是提供给javac编译器使用的,可以限定集合中的输入类型,让编译器挡住原程序中非法输入。编译器编译带类型说明的集合时会去掉“类型”信息,是程序运行效率不受影响,对于参数化的泛型类型,getClass()方法的返回值和原始的类型完全一样。由于编译生成的字节码会去掉泛型的类型信息,只要能跳过编译器,就可以往某个泛型集合中加入其他类型的数据,例如用反射得到集合,在调用其add方法即可。
package cn.itcast.day2;
import java.util.ArrayList;
public class GenericTest {
public static void main(String[] args)throws Exception{
//以前对集合的应用
ArrayList collection1 = new ArrayList();
collection1.add(1);
collection1.add(1l);
collection1.add("sdsf");
//在使用以上集合时必须要做类型转换,但由于集合中存储的是不同类型数据要转成同一种类型就会出错,
//为了解决这种问题,就出现了泛型
ArrayList<String> collection2 = new ArrayList<String>();
//使用泛型之后集合中存储的对象的类型就是固定的了。方便了使用集合。
collection2.add("sdsf");
//在使用时就不要类型转换了
String element = collection2.get(0);
//再定义一个
ArrayList<Integer> collection3 = new ArrayList<Integer>();
//看一下两个集合的字节码对象是否相同
System.out.println(collection2.getClass()==collection3.getClass());
//用反射的方法透过泛型,来添加不同类型的数据
collection3.getClass().getMethod("add", Object.class).invoke(collection3, 3);
System.out.println(collection3.get(0));
}
}
(二)泛型中的术语
1.整个ArrayList<E>称为泛型类型;E称为类型变量或类型参数,
2.整个ArrayList<Integer>称为参数化类型,里边的Integer称为类型参数的实例或实例类型参数。<>念做typeof
3.ArrayList称为原始类型。
(三)参数化类型与原始类型的兼容性:
1、参数化类型可以引用一个原始类型的对象,只不过编译器会报警告。
2、原始类型也可以引用一个参数化类型的对象,编译器也会报警高。
(四)参数化类型不考虑类型参数的继承关系
(五)在创建数组事例时,数组的元素不能使用参数化的类型。
(六)只有引用类型才能作为泛型的实际参数。
(七)自定应泛型
1、泛型方法
2、泛型类
3、静态方法的泛型(静态方法的泛型不能使用类的泛型只能在自己身上定义泛型)
(八)通过反射得到泛型的实际参数
package cn.itcast.day2;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Vector;
public class GenericParameterApply {
public static void main(String[] args)throws Exception {
// TODO Auto-generated method stub
//先通过Class类获取方法对象
Method applyMethod = GenericParameterApply.class.getMethod("applyVector", Vector.class);
//因为有些方法可能有很多泛型参数,所以返回的是数组
Type[] types = applyMethod.getGenericParameterTypes();
//得到数组中的第一个参数化类型,是ParameterizedType类型的
ParameterizedType Ptype = (ParameterizedType)types[0];
//得到这个参数化类型的原始类型
System.out.println(Ptype.getRawType());
//得到这个这个参数化类型的实例参数类型
System.out.println(Ptype.getActualTypeArguments()[0]);
}
//通过反射来获取这个方法的参数化类型的实例类型参数
public static void applyVector(Vector<String> v1){
}
}
十三、类加载器
(一)类加载器的介绍
Java提供的加载类的工具,也是一个java类。Java虚拟机安装多个类加载器,系统默认三个主要类加载器,每个类加载器负责加载特定位置的类:BootStrap、ExtClassLoader、AppClassLoader。类加载器也是Java类,那么类加载器本身也要被类加载器,显然必须有一个类加载器不是java类,这正是BootStrap。
Java虚拟机中的所有累加器采用具有父子关系的树形结构进行组织,在实例化每个类加载器对象时,需要为其制定一个父级类加载器或者默认采用系统类加载器为其父级类加载器。
package cn.itcast.day2;
public class ClassLoaderTest{
public static void main(String[] args){
// TODO Auto-generated method stub
//查看ClassLoaderTest是哪个类加载器加载的
System.out.println(ClassLoaderTest.class.getClassLoader().getClass()
.getName());
//查看System类是由哪个类加载器加载的,这个类是由BootStrap加载的,它不 是java类,所以名为空
System.out
.println(System.class.getClassLoader());
//查看类加载器的结构
ClassLoader loader = ClassLoaderTest.class.getClassLoader();
while(loader!=null)
{
System.out.println(loader.getClass().getName());
loader = loader.getParent();
}
System.out.println(loader);
}
}
(二)类加载器的委托机制
1.首先当前线程的类加载器去加载线程中的第一个类。如果类A中引用了类B,Java虚拟机将使用加载类A的类加载器来加载类B。还可以直接调用ClassLoder.loadClass()方法来指定某个类加载器去加载某个类。
2、每个类加载器加载类时,又现委托给其上级类加载器。当所有的祖宗类加载器都没有加载到类时,则回到发起者类加载器,如果还加载不了,则抛出ClassNoFoundException,而不是去找发起者类加载器的儿子,因为没有getChild方法。
(三)自定义类加载器
1、自定义类加载器必须继承ClassLoader,使用父类LoadClass()方法和defineClass()方法,覆盖findClassLoader()方法。
十四、代理
(一)代理的概念及作用
1.代理可以为已存在的多个具有相同接口的目标的各个方法增加一些系统功能,如:异常处理、日志、计算方法的运行时间、事务管理、等等。
2、编写一个与目标类具有相同接口的代理类,代理类的每个方法调用目标类的相同方法,并在调用方法加上系统功能的代码。
(二)AOP(Aspect oriented program)现象方面的编程
交叉业务的编程问题即为面向方面的编程,目标就要是交叉业务模块化,可以采用将将切面代码移动到原始方法的周围,这与直接在方法中编写切面代码的运行效果是一致的。
(三)动态代理技术
1.JVM可以在运行时期动态生成类的字节码,这种动态生成的类往往被用做代理类,即动态代理类。JVM生成的动态类必须实现一个或多个接口,所以,JVM生成的动态类只能用作具有相同接口的目标类的代理。
2.CGLIB库可以动态生成一个类的子类,一个类的子类也可以用作该类的代理,所以,如果要为一个没有实现接口的类生成动态代理类,那么可以使用CGLIB库。
3.代理类的给个方法中通常除了要调用目标的相应方法和对外返回目标返回的结果外,换可以在代码方法中的如下四个位置加上系统功能代码:
a.在调用目标方法之前
b.在调用目标方法之后
c.在调用目标方法前后
d.在处理目标方法异常的代理快中
4.JVM动态代理类的创建演示:
package cn.itcast.day3;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Collection;
public class ProxyTest {
public static void main(String[] args) {
// TODO Auto-generated method stub
//JVM使用Proxy类动态生成类演示
Class clazzProxy1=Proxy.getProxyClass(Collection.class.getClassLoader(), Collection.class );
//利用动态生成的代理类来获取它的构造方法
Constructor[] constructors=clazzProxy1.getConstructors();
for(Constructor constructor: constructors)
{
String name =constructor.getName();
StringBuilder sBuilder = new StringBuilder(name);
sBuilder.append('(');
//取出构造方法的参数
Class[]clazzParameters=constructor.getParameterTypes();
for (Class clazzParameter:clazzParameters)
{
sBuilder.append(clazzParameter.getName()).append(',');
}
//去掉最后一个‘,’
if(clazzParameters.length!=0&&clazzParameters!=null)
sBuilder.deleteCharAt(sBuilder.length()-1);
sBuilder.append(')');
System.out.println(sBuilder.toString());
}
Class clazzMethod1=Proxy.getProxyClass(Collection.class.getClassLoader(), Collection.class );
//利用动态生成的代理类来获取它的构造方法
Method[] clazzMethods=clazzMethod1.getMethods();
for(Method method: clazzMethods)
{
String name =method.getName();
StringBuilder sBuilder = new StringBuilder(name);
sBuilder.append('(');
//取出构造方法的参数
Class[]clazzParameters=method.getParameterTypes();
for (Class clazzParameter:clazzParameters)
{
sBuilder.append(clazzParameter.getName()).append(',');
}
//去掉最后一个‘,’
if(clazzParameters.length!=0&&clazzParameters!=null)
sBuilder.deleteCharAt(sBuilder.length()-1);
sBuilder.append(')');
System.out.println(sBuilder.toString());
}
}
}
5、创建动态类的实例对象及调用其方法
package cn.itcast.day3;
//这个借口是为InvocationHandler服务的
public interface Advice {
void beforeMethod();
void afterMethod();
}
//接口的实现类
package cn.itcast.day3;
public class MyAdvice implements Advice {
long beginTime = 0;
@Override
public void beforeMethod() {
// TODO Auto-generated method stub
beginTime = System.currentTimeMillis();
}
@Override
public void afterMethod() {
// TODO Auto-generated method stub
long endTime = System.currentTimeMillis();
System.out.println(endTime-beginTime);
}
}
package cn.itcast.day3;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.Collection;
public class ProxyTest {
/**
* @param args
*/
public static void main(String[] args)throws Exception {
// TODO Auto-generated method stub
//JVM使用Proxy类动态生成类演示
Class clazzProxy1=Proxy.getProxyClass(Collection.class.getClassLoader(), Collection.class );
//利用动态生成的代理类来获取它的构造方法
Constructor[] constructors=clazzProxy1.getConstructors();
for(Constructor constructor: constructors)
{
String name =constructor.getName();
StringBuilder sBuilder = new StringBuilder(name);
sBuilder.append('(');
//取出构造方法的参数
Class[]clazzParameters=constructor.getParameterTypes();
for (Class clazzParameter:clazzParameters)
{
sBuilder.append(clazzParameter.getName()).append(',');
}
//去掉最后一个‘,’
if(clazzParameters.length!=0&&clazzParameters!=null)
sBuilder.deleteCharAt(sBuilder.length()-1);
sBuilder.append(')');
System.out.println(sBuilder.toString());
}
Class clazzMethod1=Proxy.getProxyClass(Collection.class.getClassLoader(), Collection.class );
//利用动态生成的代理类来获取它的构造方法
Method[] clazzMethods=clazzMethod1.getMethods();
for(Method method: clazzMethods)
{
String name =method.getName();
StringBuilder sBuilder = new StringBuilder(name);
sBuilder.append('(');
//取出构造方法的参数
Class[]clazzParameters=method.getParameterTypes();
for (Class clazzParameter:clazzParameters)
{
sBuilder.append(clazzParameter.getName()).append(',');
}
//去掉最后一个‘,’
if(clazzParameters.length!=0&&clazzParameters!=null)
sBuilder.deleteCharAt(sBuilder.length()-1);
sBuilder.append(')');
System.out.println(sBuilder.toString());
}
//创建动态生成类的实例对象及调用其方法,因为动态生成类中只有一个带参数的构造方法所以不能直接用类来创建对象。
//要创建对象只能获取该类有参数的构造方法了
Constructor constructor =
clazzProxy1.getConstructor(InvocationHandler.class);
//用构造方法来创建对象
Collection proxy1=
(Collection)constructor.newInstance(new MyInvocationHandler1());
System.out.println(proxy1);
proxy1.clear();
//用匿名内部类的方式创建实例对象
Collection proxy2 =(Collection)constructor.newInstance(new InvocationHandler(){
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
// TODO Auto-generated method stub
return null;
}
});
//目标,方法里的内部类只能访问被final修饰的局部成员变量
final ArrayList target =new ArrayList();
//用proxy类的静态方法newProxyInstance直接把上面的方法和二为一
Collection proxy3 = (Collection)getProxy(target,new MyAdvice());
proxy3.add("zhangsan");
proxy3.add("lisi");
proxy3.add("wangwu");
System.out.println(proxy3.size());
}
private static Object getProxy(final Object target,final Advice advice) {
Object proxy3 = Proxy.newProxyInstance(
//Collection.class.getClassLoader(),
target.getClass().getClassLoader(),
//new Class[]{Collection.class},
target.getClass().getInterfaces(),
new InvocationHandler(){
//在这里就是代理和目标的集合地,创建一个目标
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
/*long beginTime = System.currentTimeMillis();
Object retVal = method.invoke(target, args);
long endTime = System.currentTimeMillis();
System.out.println(endTime-beginTime);
return retVal;*/
advice.beforeMethod();
Object retVal = method.invoke(target, args);
advice.afterMethod();
return retVal;
}
});
return proxy3;
}
}
class MyInvocationHandler1 implements InvocationHandler {
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
return null;
}
}
---------------------- android培训、java培训、期待与您交流! ----------------------