-------android培训、java培训、期待与您交流! ----------
一:Eclipse的使用技巧:
(一):切换工作间与导入项目:
(二)设置整个workspace的javac与java:设置项目存储的位置:Switch workspace---other;
(三)设置单个工程的javac与java
(四)ide(集成开发环境) --->itegrity development environment
(五) 包名:就是公司的网址或域名的反写:cn.itcast.
(六)compiler---编辑器
二:静态导入:
(一):overload---->
(二):override---->
三:可变参数与for循环增强:必须是实现了Iterable接口的数组或集合才能使用高级for
public interface Iterator<E>对 collection 进行迭代的迭代器。迭代器取代了 Java Collections Framework 中的 Enumeration。
迭代器与枚举有两点不同:
只有一个返回Iterator<T> iterator() 返回一个在一组 T 类型的元素上进行迭代的迭代器;的方法。
1: 迭代器允许调用者利用定义良好的语义在迭代期间从迭代器所指向的 collection 移除元素。
2:方法名称得到了改进。
四:基本数据类型的自动拆箱与装箱:
public static void main(String[] args) {
// TODO Auto-generated method stub
Integer i=3;//自动装箱
int is=i+4;//自动装箱
System.out.println(is);
/*
*对于这些基本数据类型的整数要装箱成一个Integer对象如果这些数字在一个字节之内(-128----127)之间的数字一旦包装成一个Integer
*对象时就会将其缓存到一个缓存池中,一旦在要new一个Integer对象的时候就会先到这个缓存池中找看又没有该对象如果有就不在new而是
*那之前的对象来返回;没有就new出来在存到缓存池中;这样比较节省空间,且使用也比较平凡所以这样做;这就是享元模式(flyweight):
*也就是说:有很多小的对象且都很多相同的部分就可以将其变成一个对象,还有其他不同的部分就让其变成外部的属性作为方法的参数传入
*参数就是外部状态,对象就是内部的状态;
*例如:
*/
Integer s=1;
i=1;
System.out.println(s==i);//对象相同
s=134;
i=134;
System.out.println(s==i);//对象不相同
}
五:枚举:(Enum):概述
为什么要定义枚举:枚举就是要某个类型的变量的取值只能为若干个固定值中的一个,否则编译器就会报错,枚举可以让编译器在编译是就可以控制
原程序中填写的非法值,普遍变量的是在开发阶段无法实现这一目标;
Enum:这是所有 Java 语言枚举类型的公共基本类。
(一) 枚举的构造函数
protected Enum(String name,int ordinal)单独的构造方法。
程序员无法调用此构造方法。该构造方法用于由响应枚举类型声明的编译器发出的代码。
(二)枚举常用的方法:
public final String name()返回此枚举常量的名称,在其枚举声明中对其进行声明。
public final int ordinal()返回枚举常量的序数(它在枚举声明中的位置,其中初始常量序数为零)。
public String toString()返回枚举常量的名称,它包含在声明中。
public final boolean equals(Object other)当指定对象等于此枚举常量时,返回 true。
public final int compareTo(E o)比较此枚举与指定对象的顺序。在该对象小于、等于或大于指定对象时,分别返回负整数、零或正整数。
public final Class<E> getDeclaringClass()返回与此枚举常量的枚举类型相对应的 Class 对象。
(三)枚举就相当于一个类,其中也就可以定义构造方法,成员变量,普通方法和抽象方法;
注意:
枚举元素必须位于枚举体中最开始的部分,枚举元素列表的最后要有分号与其他成员分隔,把枚举中的成员方法或变量等放在枚举元素的前面
编译会报告错误;
(四):带构造方法的枚举:
构造方法必须定义成私有的;如果有多个构造方法,该选择哪个呢?可以在枚举对象中使用大括号来指定要调用的哪个枚举:
在枚举类中的某个类中后面加()括号该枚举类调用的构造方法还是没有参数的构造方法;
六:反射的基石--->Class类的概述:反射就把java类中的各种成分映射成相应的java类
(一):java类用于描述一类事物的共性,该类事物有什么属性,没有什么属性,至于这个属性的值是什么,则由这个类的实例对象来确定,不同的实例
对象有不同的属性值,java程序中的各个java类他们是否属于同一类事物,是不是可以用一个类来描述这个类的事物呢?描述这类事物的Java类名
就是Class;
(二) 注意的是这个Class与小写的class关键字的区别:Java的Class类是描述类名,类的访问属性,类所属于的包名,字段名称的列表,
方法名称的列表等等;而小写的类class是描述某一事物所拥有的一些属性和方法构造方法、修饰符等信息;
(三):字节码就是一个类被类加载器加载到内存中,占用一片存储空间,这个空间里面的内容就是类的字节码,不同的是类的字节码是不同的,所以他们在内存
中的内容是不同的,这一个个的空间可分别用一个个的对象来表示,这些对象显然具有相同的类型;
(四):获取字节码的方式有三种:
1:类名.class;例如:System.class;
2:对象.getClass();例如:new Date().getClass();
3:Class.forName("类名");例如:new Date().forName("java.util.Date");
(五):九个预定义Class实例对象:
Boolean.TYPE, Character.TYPE, Byte.TYPE, Short.TYPE, Integer.TYPE, Long.TYPE, Float.TYPE, Double.TYPE, Void.TYPE
例如:
Int.class==Integere.TYPE;
数组类型的Class实例对象:Class.isArray();
小结:总之只要是在源程序中出现的类型,都有个自的Class实例对象;
(六):Constructor(构造器)类代表获取某个类中的一个构造方法;那么用什么方法可以区分清楚想得到其中的那个方法呢?可以根据参数的个数和类型:
(1)得到某个类的所有构造方法:
(2)得到某一个构造方法:
(3)创建实例对象:
如示例:
public static void main(String[] args)throws Exception {
// TODO Auto-generated method stub
//通过getConstructor方法获取String类的的构造方法参数是(StringBuffer类型的)
Constructor constructor= String.class.getConstructor(StringBuffer.class);
//通过反射方式创建实例对象
String str=(String)constructor.newInstance(new StringBuffer("abc"));
System.out.println(str);
//通过getConstructor方法获取Student类的指定的构造函数;
Constructor constructors=Student.class.getConstructor(String.class,int.class);
//通过反射创建Student实例对象
//newInstance(实例):使用此 Constructor 对象表示的构造方法来创建该构造方法的声明类的新实例,并用指定的初始化参数初始化该实例。
Student student=(Student) constructors.newInstance("张三",20);
System.out.println(student.name+"...."+student.age);
}
class Student{
String name;
int age;
public Student(String name,int age){
this.name=name;
this.age=age;
}
public String toString(){
return name+age;
}
}
//小结:如果传入的参数不对就会遇到NoSuchMethodException该异常:没有改构造方法;
(七)Field类代表某个类中的成员变量:
public static void show() throws Exception{
//获某个类的构造函数
//通过getConstructor方法获取String类的的构造方法参数是(StringBuffer类型的)
Constructor constructor= String.class.getConstructor(StringBuffer.class);
//通过反射方式创建实例对象
String str=(String)constructor.newInstance(new StringBuffer("abc"));
System.out.println(str);
//通过getConstructor方法获取Student类的指定的构造函数;
Constructor constructors=Student.class.getConstructor(String.class,int.class);
//通过反射创建Student实例对象
Student student=(Student) constructors.newInstance("张三",20);
System.out.println(student.getName()+"...."+student.age);
//获取某个类里面的字段
Field field=student.getClass().getField("age");
Object age=field.get(student);
System.out.println(age);
//通过getDeclaredField方法来获取私有的成员
field=student.getClass().getDeclaredField("name");
field.setAccessible(true);
Object name=field.get(student);
System.out.println(name);
/*
* field=student.getClass().getField("name");
* Exception in thread "main" java.lang.NoSuchFieldException: name
* 异常:NoSuchFieldException没有找到要找的字段
* 异常:Exception in thread "main" java.lang.IllegalAccessException:
* 不能获取该私有字段?解决:field.setAccessible(true);通过该方法设置为可获取
*/
}
class Student{
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int age;
public Student(String name,int age){
this.name=name;
this.age=age;
}
public String toString(){
return name+age;
}
}
(八)Method类代表某个类中的一个成员方法:
Method 提供关于类或接口上单独某个方法(以及如何访问该方法)的信息。所反映的方法可能是类方法或实例方法(包括抽象方法)。
Method 允许在匹配要调用的实参与底层方法的形参时进行扩展转换;但如果要进行收缩转换,则会抛出 IllegalArgumentException。
public Class<?> getDeclaringClass()返回表示声明由此 Method 对象表示的方法的类或接口的 Class 对象。
(九)数组的反射:
(1)具有相同的维数和元素类型的数组属于同一个类型,既具有相同的Class实例对象;
(2)代表数组的Class实例对象的getSuperClass()方法返回的父类Object类对应的Class;
(3)基本类型的一维数组可以被当做Object类型使用,不能当做Object[]类型使用,非基本数据类型的一维数组既可以被当做Object类型使用有可以被当
做Object[ ]类型使用。
(4)Arrays.asList()方法处理int[]和String[]时的差异。
如示例:
public static void main(String[] args) {
// TODO Auto-generated method stub
int[] i=new int[]{1,2,5};
//Integer[] i=new Integer[]{1,2,5};
String[] s=new String[]{"as","ds","df"};
System.out.println(i);//获取到的是该数组的内存地址
System.out.println(s);
List list=Arrays.asList(i);//获取到的还是该数组的内存地址
System.out.println(list);
list=Arrays.asList(s);//数组的类型转换
System.out.println(list);//这时就可以获取到数组中的值了
/*
* 其原因是因为int是基本数据类型而不是Object类型的如果将int数组改为Integer[] i=new Integer[]{1,2,5};
* 就可以获取数组中的数据了或是该为二维数组也可以;
*/
}
(5)Arrays工具类用于完成对数组的反射操作。
(十)hashCode和HashSet的关系:
(1):HashSet就是在采用哈希算法存取对象的集合,它内部采用了对某个数字N进行取余的方式对哈希码进行分组和划分对象的存储区域。Object类中定义
从HashSet集合中查找某个对象是,java系统首先调用对象的hashCode方法获取该对象的哈希码,然后根据哈希码找到相应的存储区域最后取出该存储
区域的每一元素与该对象进行equals方法比较这样就不用遍历集合中的所有元素就可以得到结论了;
(2):只要类的实例对象要被采用哈希算法进行存储和检索式,那么这个类就需要按要求覆盖hashCode()方法,即使程序可能暂时不会用到当前类的hashcode()
方法但是为它提供了hashCode()方法也不会有什么不好的,所以通常要求覆盖hashCode()方法和equals()方法;
(3):什么是内存泄露:
其实就是在程序中有的对象已经不用了,但一直还是存在于内存中没有释放,这样长时间就会造成对象越来越多就造成了内存溢出;
(4):为什么会造成内存溢出呢?
当对底层是哈希结构的集合操作时;当一个对象被存入集合中以后,就不能修改这个对象的那些参与计算哈希值的字段了,否则对象被修改后
就会让原来的哈希值从新生成,这时在对原来的对象的哈希值和新生成的哈希值就不同,在这种情况下即使在contains方法使用该对象的当前
引用作为参数去集合中检索对象,也将返回找不到对象的结果,这也会导致无法从集合中单独删除当前对象,从而造成内存泄露(内存溢出);
例如示例:
public static void main(String[] args) {
// TODO Auto-generated method stub
Collection collection=new HashSet();
Student s1=new Student("张三",22);
Student s2=new Student("王五",22);
Student s3=new Student("赵六",22);
Student s4=new Student("张三",22);
collection.add(s1);
collection.add(s2);
collection.add(s3);
collection.add(s4);
//修改与不修改的结果不一样s1.age=4;
s1.age=4;
collection.remove(s1);
System.out.println(collection.size());
}
(十一)配置文件的加载方式:
如示例:
public static void main(String[] args) throws IOException, InstantiationException, IllegalAccessException,
ClassNotFoundException {
// TODO Auto-generated method stub
//配置文件的内容:className=java.util.ArrayList
//创建字节流
//InputStream ips=new FileInputStream("ReflectFile.properties");
//通过类加载器在加载java的class文件的同时将配置文件也加载进去(getResourceAsStream)---->类加载器
InputStream ips=ReflectHasSet.class.getResourceAsStream("ReflectFile.properties");
//当配置文件在一个包中的时候使用下面这种方式
//InputStream ips=ReflectHasSet.class.getResourceAsStream("/ReflectFile/ReflectFile.properties");
//Properties 类表示了一个持久的属性集。Properties 可保存在流中或从流中加载。属性列表中每个键及其对应值都是一个字符串。
Properties porperties=new Properties();
//使用Properties类的load(InputStream inStream)方法 从输入流中读取属性列表(键和元素对)。
porperties.load(ips);
ips.close();//关闭流
//通过key获取配置文件中的类名
String className=porperties.getProperty("className");
//通过反射获取集合
Collection collection=(Collection)Class.forName(className).newInstance();
//Collection collection=new HashSet();
Student s1=new Student("张三",22);
Student s2=new Student("王五",22);
Student s3=new Student("赵六",22);
Student s4=new Student("张三",22);
collection.add(s1);
collection.add(s2);
collection.add(s3);
collection.add(s4);
s1.age=4;
/*
当对底层是哈希结构的集合操作时;当一个对象被存入集合中以后,就不能修改这个对象的那些参与计算哈希值的字段了,否则对象被修改后
就会让原来的哈希值从新生成,这时在对原来的对象的哈希值和新生成的哈希值就不同,在这种情况下即使在contains方法使用该对象的当前
引用作为参数去集合中检索对象,也将返回找不到对象的结果,这也会导致无法从集合中单独删除当前对象,从而造成内存泄露(内存溢出);
*/
collection.remove(s1);
System.out.println(collection.size());
}
七:javaBean内省(IntroSpector)概述:
JavaBean是一个特殊的Java类,主要用于传递数据信息,这种java类中的方法主要用于访问私有的字段,且方法名符合某种命名规则;
(一)例如:如果要在两个模块之间传递多个信息,可以讲这些信息封装到一个JavaBean中,这种JavaBean的实例对象通常称之为值对象(Value Object,
简称:VO)。这些信息在类中用私有字段来存储,如果读取或设置这些字段的值,则需要通过一些相应的方法来访问。这就是(将类中属性封装后提供的
get和set方法);JavaBean的属性是根据其中的setter和getter方法来确定的,而不是根据其中的成员变量。如果方法名为setName。中文意思即是设置
姓名(name);如果方法名为getName则就是获取(name);其实就是去除前缀set或get获取后面的单词;
注意:如果剩余部分的第二个字母是小写,则将剩余部分的首字母改成小写的;
例如:
setName()的属性名---->name;
isLast() 的属性名---->last;
getCPU() 的属性名---->CPU;
小结:一个类被当做javaBean来使用时,javaBean的属性是根据方法名来推断出来的,因为无法看到java内部封装的成员变量;
一个符合javaBean特点的类可以当作一个普通的类来使用,在javaEE开发中基本都是要按照JavaBean来进行操作的;在JDK中提供了对JavaBean
进行操作的一些API。这套API就称之为内省:
(二):使用JavaBean来设置和获取某个类的指定成员变量值;主要是通过PropertyDescriptor类来获取get和set方法来完成:
如示例:
public void show() throws IntrospectionException, IllegalArgumentException, IllegalAccessException, InvocationTargetException{
IntroSpectorTest ipt=new IntroSpectorTest("zhangs",22);
//通过PropertyDescriptor这个类来设置IntroSpectorTres类的name成员变量
PropertyDescriptor pd=new PropertyDescriptor("name",ipt.getClass());
//这里就是获取JavaBean的set方法
Method method=pd.getWriteMethod();
//在通过这个方法来个那个类设置值
method.invoke(ipt,"王五");
//PropertyDescriptor pd1=new PropertyDescriptor("name",ipt.getClass());//可省略
//这里就是获取JavaBean的get方法
Method methods=pd.getReadMethod();
//获取get方法返回的值
Object retval=methods.invoke(ipt);
System.out.println(retval);
}
//自定义类 : IntroSpectorTest
class IntroSpectorTest{
public IntroSpectorTest(String name, int age) {
super();
this.name = name;
this.age = age;
}
private String name;
private int 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;
}
}
八:了解注解及java提供的几个注解:
(一)注解:
1:@SuppressWarnings("deprecation")---->压缩警告注解;
System.runFinalizersOnExit(true);
2:@Deprecated --->方法 过时的警告:
@Deprecated
public static void sayHello(){
System.out.println("方法的主体");
}
3:@Override:方法的覆盖注解;
(二):小结:
注解相当于一种表记,在程序中加了注解就等于为程序打上了某种标记,没加则等于没有某种标记,以后再java编译器,开发工具盒其他程序可以用反射
来了解 你的类及各种元素上有没有何种标记,看你有什么标记,就去干相应的事,标记可以加在包、类、字段、方法、方法的参数以及局部变量上;
在java.lang包中可以看到JDK中提供的最基本的annotation(主解);
(三): 注解就相当于一个你的源程序中药调用的一个 类,要在源程序中应用某个注解,得先准备好了一个注解类,就像你要调用的某个类,要先有开发好这个类;
(一)步骤为:
1:注解类;
2:应用了注解类的类;
3:对应用了注解类的类进行反射操作的类;
4:注解可以用(@Reteion元注解设置其某个指定的注解的生命周期)共有三种取值方式分别是:
java源文件:@ReteionPolicy.SOURCE
Class文件:@ReteionPolicy.CLASS
内存中的字节码:@ReteionPolicy.RUNTIME
5:@Target元注解:Targe的默认值为任何元素,设置Targe等于ElementType.METHOD,原来加在类上的注解就会报错改用为数组方式设置为:
{ElementType.METHOD,ElementType.TYPE}就可以了;
6:可以再API文档中的java。lang.annotion包下面的类就可以直接查看;
如示例:
@ItcastAnnotation
class AnnotationTests{
@ItcastAnnotation
public static void show(){
if(AnnotationTests.class.isAnnotationPresent(ItcastAnnotation.class)){
//获取ItcastAnnotation类的对象
ItcastAnnotation annotation=(ItcastAnnotation)AnnotationTests.class.getAnnotation(ItcastAnnotation.class);
System.out.println(annotation);
}
}
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 {
//设置注解的值,如不设置则为默认值
String name() default "王五";
String value();//注解中的特殊属性值
String[] str() default{"数组默认值1","数组默认值2"};
}
(四):注解的属性:一个注解相当于一个标记,这时就可以知道是属于哪个类的;如果还想更细就可以为其添加属性来进行区分:
如何定义基本类型的属性和应用属性呢?
//自定义的注解类
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD,ElementType.TYPE})
public @interface ItcastAnnotation {
//设置注解的值,如不设置则为默认值
String name() default "王五";
String value();//注解中的特殊属性值
String[] str() default{"数组默认值1","数组默认值2"};
}
//使用注解类
@ItcastAnnotation(name="设置的值1",value="设置的值2",str={"数组值1","数组值1"})
class AnnotationTests{
@ItcastAnnotation("设置的值2")
public static void show(){
if(AnnotationTests.class.isAnnotationPresent(ItcastAnnotation.class)){
//获取ItcastAnnotation类的对象
ItcastAnnotation annotation=(ItcastAnnotation)AnnotationTests.class.getAnnotation(ItcastAnnotation.class);
System.out.println(annotation);
//获取注解中的注解信息值;
System.out.println(annotation.value());
System.out.println(annotation.str().length);
//循环获取注解中数组的值
for (int i = 0; i <annotation.str().length; i++) {
System.out.println(annotation.str()[i]);
}
}
}
}
十:泛型类概述:
(一)什么是泛型:
ArrayList<E>:这个集合称为泛型集合,<E>是泛型变量或是说是这个集合的类型;
ArrayList<String>:称为参数化的类型;而这个String就集合的类型的实际参数类型或是参数实例;
ArrayList:这个集合则称为原始类型;
(二)泛型中的类型参数严格说明集合中装载的数据类型是什么,和可以加载什么样的类型参数数据:
记住 :Collection<String>和Collection<Object>是两个没有转换关系的参数化的类型;
例如:Vector<String> v=new Vector<Object>();如果可以的话就可以取出v对象的String类型,而v的实际指向的对象中可以加入任意的类型对象;
Vector<Object> v=new Vector<String>();可以的话那么以后可以向v中加入任意的类型对象,而v实际指向集合中的是只能是String类的对象;
(三)泛型是提供给javac编译器使用的,可以限定集合中的输入类型,让编译器挡住源程序中的非法输入,编译器编译带类型说明的集合时会去掉集合中的
(类型)信息,是程序运行效率不受影响,对于参数化的泛型类型的getClass()方法的返回值和原始值完全一样,由于编译生成的字节码会去掉泛型的类
型信息,只要跳过编译器就可以往某个泛型集合中加入其它类型的数据;
如示例:使用反射得到集合在调用集合中的add方法来添加数据:
public static void show()throws Exception{
//定义一个泛型集合类型为Student类的类型
ArrayList<Student> list=new ArrayList<Student>();
//通过反射获取list集合的某个方法
Method method=list.getClass().getMethod("add", Object.class);
//通过获取的add方法给集合赋非泛型里的Student类型的值
method.invoke(list, "王五");
//获取值
System.out.println(list.get(0));
method.invoke(list, "王五,25");
System.out.println(list.get(1));
}
(四)泛型中的 ? 通配符 ;
示例:定义一个方法,该方法用于打印出任意参数化类型的集合中的所有数据;
public satic void printCollection(Collection<?> cols){
for(Object object:cols){
System.out.println(object);
}
cols.add("String");//这里会报错因为?还不知道自己的类型
cols.size();//这是共性的方法;
cols=new HashSet<Date>();//将这个集合当做参数传给Collection<?> cols;
}
小结:使用?通配符可以引用其他各种参数化的类型,?通配符定义的变量主要用作引用,可以调用与参数化无关的方法,不能调用与参数有关的方法;
(五):泛型限定通配符:
1:限定通配符的上边界:
Vector<? extends Number> x=new Vector<Integer>;
这是指这个能指定的泛型只能是Number类型之内的;不能使其他的类型,为其指定上限为Number;
2:限定通配符的下边界:
Vector<? super Integer> x=new Vector<Integer>;
这是指这个能指定的泛型只能是Number类型之内的;不能使其他的类型,但是其指定下限为Integer;
注意:限定通配符总是包括自己;
(六):泛型类:
1:如果累的实例对象中的多处都要用到同一个泛型参数,即可在这些地方引用的泛型要保持同一个实际类型时,这时候就泛型的方式进行定义,也就是类级别。
例如:
public class NewsDao<t>{
public void save(T obj){}
}
注意:
1:类级别的泛型是根据引用该类名是指定的类型信息来参数化类型变量:在对泛型进行参数化时类型参数的实例必须是引用类型不能使基本类型;
2:当一个变量被声明为泛型是,只能被实例变量的方法调用(还有内嵌类型),而不能被静态变量和静态方法调用,因为静态成员是被所有参数化的类所共享的
所以静态成员不应该有类级别的类型参数;
十一:类加载器概述:
java虚拟机中可以安装多个类加载器,系统默认三个主要类加载器(BootStrap 、ExtClassLoader 、 AppClassLoader),每一个类加载器负责特定位置的类:
类加载器以就是java类。因为其他是java类的类加载器本身也要被类加载器加载,显然必须有一个类加载器这个就BootStrap;
(一)类加载器的委托机制:每一个类在加载类时,是先委托给其上一级加载器;当所有的上一级加载器没有加载到类时,就会给发起者类加载器,还加载不了则就
抛出ClassNotFoundException异常;不是在去找发起者类加载器的子类;因为没有getchild方法。即使有要是有多个子类有会找那一个呢,所以不会在找了;
(二)面试题:
能不能自己写一个类叫:java.lang.System:
回答:可以写:但是运行不到罢了:因为累加载器采用委托机制,这样可以保证父级优先,也就是总是使用父级门能找到的类。这样就总是使用java提供给的
System类;这也就是委托机制,由最上级找,找不到在由最上到下,而System类就在最上级的加载器的加载范围中;
十二:代理的概念与作用:
(一)在程序中的代理就是要为已存在的多个具有相同接口的目标类的个各方法增加一些系统功能;例如:为写好的程序增加异常处理,日志,事物 等等 ;都可
以使用代理;在JVM可以再运行期动态生成出类的字节码。着中国动态生成的类往往被用作代理类,即动态代理;
(二)代理的使用:
(1)JVM生成的动态类必须实现一个或多个接口,所以JVM生成的动态类只能用作具有相同接口的目标类的代理;
(2)另一种是CGLIB库可以动态生成一个类的子类。一个类的子类也可以用作该类的代理。所以如果要一个没有实现接口的类生成动态代理的类那么可以用
CGLIB库;
(3)代理类的各个方法中通常处理要调用目标的相应方法和对外返回的结果外。还可以在代理方法中的四个位置加上系统功能代码:如下
1:在调用目标方法前:
2:在调用目标方法后
3:在调用目标方法的前后
4:在处理目标方法异常的catch块中;
(四)Proxy类:
Proxy 提供用于创建动态代理类和实例的静态方法,它还是由这些方法创建的所有动态代理类的超类。
如示例:动态生成代理器
public class RealizeProxy {
//创建代理的方法(动态代理的目标---接口类名)
public static Object getProxy(final Object target,final Advice advice){
//动态代理的实现(类的加载器,接口,内部类的实现)
Object proxy=Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(),new InvocationHandler(){
@Override//覆盖类的方法
public Object invoke(Object proxy, Method method,
Object[] args) throws Throwable {
advice.Upload(method);//为目标添加的接口的实现方法
/*
* 客户端在调用代理的某个方法时要传入的三个参数分别为:
* 1:调用哪个代理对象;2:调用代理对象的哪个方法;3:调用代理对象的哪个方法的参数
*/
//调用目标的方法
Object retVal=method.invoke(target, args);
advice.Downloads(method);//为目标添加的接口的实现方法
return retVal;
}
});
return proxy;//返回目标对象
}
}
//接口
public interface Advice {
public void Upload(Method method);
public void Downloads(Method method);
}
//实现接口类
public class MyAdvice implements Advice {
@Override//为目标多添加的方法
public void Downloads(Method method) {
System.out.println("Hello work");
System.out.println(method.getName()+"------"+System.currentTimeMillis()/10000);
}
@Override
public void Upload(Method method) {
System.out.println("Hello world");
System.out.println(method.getName()+"------"+System.currentTimeMillis()/10000);
}
}
public static void main(String[] args) {
// TODO Auto-generated method stub
final ArrayList list=new ArrayList();
MyAdvice myadive=new MyAdvice();
Collection cll=(Collection)RealizeProxy.getProxy(list, new MyAdvice());
cll.add("sdf");
cll.add("sdf");
}
-------android培训、java培训、期待与您交流! ----------