您的位置:首页 > 编程语言 > Java开发

java高新技术.其他

2014-08-21 20:11 197 查看
1:自动拆装箱:

java中数据类型分为两种 :

基本数据类型

引用数据类型(对象)

在 java程序中所有的数据都需要当做对象来处理,针对8种基本数据类型提供了包装类,如下:

int --> Integer 

byte --> Byte 

short --> Short

long --> Long 

char --> Character 

double --> Double

float --> Float 

boolean --> Boolean 

jdk5以前基本数据类型和包装类之间需要互转:

基本---引用 Integer x = new Integer(x); 

引用---基本 int num = x.intValue(); 

1)、Integer x = 1; 

    x = x + 1;经历了什么过程 装箱----拆箱----装箱; 

2)、为了优化,虚拟机为包装类提供了缓冲池,Integer池的大小-128~127 一个字节的大小;
3)、String池:Java为了优化字符串操作  提供了一个缓冲池;

2:枚举:

关键字 enum

枚举就是要让某个类型的变量的取值只能为若干固定值之中的一个。

是一个特殊的类,其中的每一个元素都是该类的一个对象。

注意 : 因为不能New 枚举的实力,所以枚举不能继承其他类,也不能被其他类继承。

 为什么要有枚举?

      问题:要定义星期几或性别的变量,该怎么定义?假设用1-7分别表示星期一到星期日,但有人可能会写成int weekday = 0;或即使使用常量方式也无法阻止意外。

枚举就是要让某个类型的变量的取值只能为若干个固定值中的一个,否则,编译器就会报错。枚举可以让编译器在编译时就可以控制源程序中填写的非法值,普通变量的方式在开发阶段无法实现这一目标。

 

    用普通类如何实现枚举功能,定义一个Weekday的类来模拟枚举功能。 

    1、私有的构造方法。

    2、每个元素分别用一个公有的静态成员变量表示。

     可以有若干公有方法或抽象方法。采用抽象方法定义nextDay就将大量的if.else语句转移成了一个个独立的类

 enum TrafficLamp{
/**
* 对于这道题目而言,使用的其实是匿名对象内部类!
* 枚举最简单的创建对象方法:RED,YELLOW,GREEN
* 对于普通的类而言,创建对象:Person p = new Person();

*/
RED(30){
public TrafficLamp nextLamp() {
return YELLOW;
}

},
YELLOW(40){
public TrafficLamp nextLamp() {
return GREEN;
}
},
GREEN(45){
public TrafficLamp nextLamp() {
return RED;
}
};
public abstract TrafficLamp nextLamp();
private int time;
private TrafficLamp(int time){
this.time = time;
}
public int getTime() {
return time;
}
public void setTime(int time) {
this.time = time;
}

}

public class EnumDemo4 {
public static void main(String[] args) {
System.out.println(TrafficLamp.RED.nextLamp());
System.out.println(TrafficLamp.RED.nextLamp().getTime());
}

}

3:初识JavaBean与内省

内省:IntroSpector

·JavaBean是一种特殊的Java类,主要用于传递数据信息,这种java类中的方法主要用于访问私有的字段,且方法名符合某种命名规则。

·如果要在两个模块之间传递多个信息,可以将这些信息封装到一个JavaBean中,这种JavaBean的实例对象通常称之为值对象(Value Object,简称VO)。这些信息在类中用私有字段来存储,如果读取或设置这些字段的值,则需要通过一些相应的方法来访问。

·JavaBean的属性是根据其中的setter和getter方法来确定的,而不是根据其中的成员变量。如果方法名为setId,中文意思即为设置id,至于你把它存到哪个变量上,则不用管。如果方法名为getId,中文意思即为获取id,至于你从哪个变量上取,也不用管。去掉set前缀,剩余部分就是属性名,如果剩余部分的第二个字母是小写的,则把剩余部分的首字母改成小的。

例如:

setId()的属性名:id

isLast()的属性名:last

setCPU的属性名:CPU

getUPS的属性名:UPS

总之,一个类被当作javaBean使用时,JavaBean的属性是根据方法名推断出来的,它根本看不到java类内部的成员变量。

·一个符合JavaBean特点的类可以当作普通类一样进行使用,但把它当JavaBean用肯定需要带来一些额外的好处,我们才会去了解和应用JavaBean!

好处如下:

1-在Java EE开发中,经常要使用到JavaBean。很多环境就要求按JavaBean方式进行操作。

2-JDK中提供了对JavaBean进行操作的一些API,这套API就称为内省。如果要你自己去通过getX方法来访问私有的x,怎么做,有一定难度吧?用内省这套api操作JavaBean比用普通类的方式更方便。

2. 对JavaBean的简单内省操作

通过内省的方式对ReflectPoint对象中的成员变量进行读写操作。

示例:

public class ReflectPoint {

       private int x ;

       private int y ;

      

       public ReflectPoint(int x, int y) {

             super();

             this.x = x;

             this.y = y;

      }

      public int getX() {

             return x ;

      }

       public void setX(int x) {

             this.x = x;

      }

       public int getY() {

             return y ;

      }

       public void setY(int y) {

             this.y = y;

      }

}

import java.beans.PropertyDescriptor;

import java.lang.reflect.Method;

public class ReflectTest {

       public static void main(String[] args) throws Exception {

         ReflectPoint pt1 = new ReflectPoint(3, 5);

        

         String propertyName = "x";

         PropertyDescriptor pd1 = new PropertyDescriptor(propertyName, pt1.getClass());

         Method readMet
4000
hod = pd1.getReadMethod();

         Object retVal = readMethod.invoke(pt1);

         System. out.println(retVal);

         //结果:3

        

         PropertyDescriptor pd2 = new PropertyDescriptor(propertyName, pt1.getClass());

         Method writeMethod = pd2.getWriteMethod();

         Object value = 7;

         writeMethod.invoke(pt1,value);

         System. out.println(pt1.getX());

         //结果:7

       }

}

4:注解是java 的一个新的类型(与接口很相似),它与类、接口、枚举是在同一个层次,它们都称作为java 的一个类型(TYPE)。它可以声明在包、类、字段、方法、局部变量、方法参数等的前面,用来对这些元素进行说明,注释。它的作用非常的多,例如:进行编译检查、生成说明文档、代码分析等。

JDK提供的几个基本注解

a. @SuppressWarnings

该注解的作用是阻止编译器发出某些警告信息。

它可以有以下参数:

deprecation:过时的类或方法警告。

unchecked:执行了未检查的转换时警告。

fallthrough:当Switch 程序块直接通往下一种情况而没有Break 时的警告。

path:在类路径、源文件路径等中有不存在的路径时的警告。

serial:当在可序列化的类上缺少serialVersionUID 定义时的警告。

finally:任何finally 子句不能完成时的警告。

all:关于以上所有情况的警告。

b. @Deprecated

该注解的作用是标记某个过时的类或方法。

c. @Override

该注解用在方法前面,用来标识该方法是重写父类的某个方法。

元注解

a. @Retention

它是被定义在一个注解类的前面,用来说明该注解的生命周期。

它有以下参数:

RetentionPolicy.SOURCE:指定注解只保留在一个源文件当中。

RetentionPolicy.CLASS:指定注解只保留在一个class 文件中。

RetentionPolicy.RUNTIME:指定注解可以保留在程序运行期间。

b. @Target

它是被定义在一个注解类的前面,用来说明该注解可以被声明在哪些元素前。

它有以下参数:

ElementType.TYPE:说明该注解只能被声明在一个类前。

ElementType.FIELD:说明该注解只能被声明在一个类的字段前。

ElementType.METHOD:说明该注解只能被声明在一个类的方法前。

ElementType.PARAMETER:说明该注解只能被声明在一个方法参数前。

ElementType.CONSTRUCTOR:说明该注解只能声明在一个类的构造方法前。

ElementType.LOCAL_VARIABLE:说明该注解只能声明在一个局部变量前。

ElementType.ANNOTATION_TYPE:说明该注解只能声明在一个注解类型前。

ElementType.PACKAGE:说明该注解只能声明在一个包名前。

注解的生命周期

一个注解可以有三个生命周期,它默认的生命周期是保留在一个CLASS 文件,但它也可以由一个@Retetion 的元注解指定它的生命周期。

a. java 源文件

当在一个注解类前定义了一个@Retetion(RetentionPolicy.SOURCE)的注解,那么说明该注解只保留在一个源文件当中,当编译器将源文件编译成class 文件时,它不会将源文件中定义的注解保留在class 文件中。

b. class 文件中

当在一个注解类前定义了一个@Retetion(RetentionPolicy.CLASS)的注解,那么说明该注解只保留在一个class 文件当中,当加载class 文件到内存时,虚拟机会将注解去掉,从而在程序中不能访问。

c. 程序运行期间当在一个注解类前定义了一个@Retetion(RetentionPolicy.RUNTIME)的注解,那么说明该注解在程序运行期间都会存在内存当中。此时,我们可以通过反射来获得

定义在某个类上的所有注解。

注解的定义

一个简单的注解:

public @interface Annotation01 {

//定义公共的final静态属性

.....

//定以公共的抽象方法

......



a. 注解可以有哪些成员

注解和接口相似,它只能定义final 静态属性和公共抽象方法。

b. 注解的方法

1.方法前默认会加上public abstract

2.在声明方法时可以定义方法的默认返回值。

例如:

String color() default "blue";

String[] color() default {"blue", "red",......}

3.方法的返回值可以有哪些类型

8 种基本类型,String、Class、枚举、注解及这些类型的数组。

c. 使用注解(参照下面的注解使用)

注解的使用

注解的使用分为三个过程。

定义注解-->声明注解-->得到注解

a. 定义注解(参照上面的注解定义)

b. 声明注解

1. 在哪些元素上声明注解

如果定义注解时没有指定@Target 元注解来限制它的使用范围,那么该注解可以使用在ElementType 枚举指定的任何一个元素前。否则,只能声明在@Target 元注解指定的元素前。

一般形式:

@注解名()

2. 对注解的方法的返回值进行赋值

对于注解中定义的每一个没有默认返回值的方法,在声明注解时必须对它的每一个方法的返回值进行赋值。

一般形式:

@注解名(方法名=方法返回值,、、、、、、)

如果方法返回的是一个数组时,那么将方法返回值写在{}符号里

@注解名(方法名={返回值1,返回值2,、、、、、、},、、、、、、、)

3. 对于只含有value 方法的注解,在声明注解时可以只写返回值。

c. 得到注解

对于生命周期为运行期间的注解,都可以通过反射获得该元素上的注解实例。

1、声明在一个类中的注解

可以通过该类Class 对象的getAnnotation 或getAnnotations 方法获得。

2、声明在一个字段中的注解

通过Field 对象的getAnnotation 或getAnnotations 方法获得

3、声明在一个方法中的注解

通过Method 对象的getAnnotation 或getAnnotations 方法获得

总结

注解可以看成是一个接口,注解实例就是一个实现了该接口的动态代理类。

注解大多是用做对某个类、方法、字段进行说明,标识的。以便在程序运行期间我们通过反射获得该字段或方法的注解的实例,来决定该做些什么处理或不该进行什么处理  

5:类加载器:就是加载类的工具。

JAVA虚拟机中可以安装多个类加载器,系统默认三个主要的类加载器,每个类负责加载特定位置的类。

 BootStrap-------ExtClassLoader------AppClassLoader classpath指定的类加载器

    父级              子集               子子集

类加载器也是JAVA类,因为其他是JAVA类的类加载器背身也要被类加载其加载。显然必须有第一个类加载器不是jAVA类,这正是BootStrap;所以类加载器

是用BootStrap加载的。

Java虚拟机中的所有类装载器采用具有父子关系的树形结构进行组织,在实例化每个类装载器对象时,需要为其指定一个父级类装载器对象或者默认采用系统类装载器为其父级类加载。 

类名.class.getClassLoader().getClass().getname();获取类加载器名称。

类加载器的委托机制:

当Java虚拟机要加载一个类时,到底派出哪个类加载器去加载呢?

首先当前线程的类加载器去加载线程中的第一个类。

如果类A中引用了类B,Java虚拟机将使用加载类A的类装载器来加载类B。 

还可以直接调用ClassLoader.loadClass()方法来指定某个类加载器去加载某个类。

每个类加载器加载类时,又先委托给其上级类加载器。

类加载器是类的加载工具,主要有三种类加载器 一种是BootStrap  一种是ExtClassLoader  一种是 AppClassLoader 

自定义类加载器:

   首先,类加载器必须要继承ClassLoader。 覆盖findClss

6:代理类

程序中的代理:要为已存在的多个具有相同接口的目标类的各个方法增加一些系统功能,例如:异常处理、日志、计算方法的运行时间、事务管理、等等。

代理类要调用目标类的功能。

目标类  doSomeThing(){

        业务功能代码

            }

代理类  doSomeThing(){

          //前置系统功能代码

           目标对象.doSomeThing()

          //后置系统功能代码   

         }

动态代理的工作原理:

1)Client(客户端)调用代理,代理的构造方法接受一个InvocationHandler,client调用代理的各个方法,代理的各个方法请求转发给刚才通过构造方法传入的handler对象,又把各请求分发给目标的相应的方法。就是将handler封装起来,其中this引用了当前的放(发来什么请求就接受哪个方法)。

猜想分析动态生成的类的内部代码:

1、动态生成的类实现了Collection接口(可以实现若干接口),生成的类有Collection接口中的所有方法和一个如下接受InvocationHandler参数的构造方法。

2、构造方法接受一个InvocationHandler对象,接受对象了要干什么用呢?该方法内部的代码会是怎样的呢?

实现Collection接口的动态类中的各个方法的代码又是怎样的呢?InvocationHandler接口中定义的invoke方法接受的三个参数又是什么意思?图解说明如下:

分析为什么动态类的实例对象的getClass()方法返回了正确结果呢?

为何动态类的实例对象的getClass()方法返回了正确结果,而没调用invoke方法:

因为代理类从Object上继承了许多方法,其中只对三个方法(hashCode、equals和toString)进行开发,委托给handler去自行处理,对于它身上其他方法不会交给代理类去实现,所以对于getClass()方法,还是由Object本身实现的。即proxy3.getClass(),该是什么结果还是什么结果,并不会交给invoke方法处理。

自定义代理类的步骤:

方式1:

             获得动态代理类的字节码文件
Class claz=Proxy.getProxyClass(Collection.class.getClassLoader(), Collection.class);
//通过反射获得该动态代理类的构造方法
Constructor c=claz.getConstructor(InvocationHandler.class);
    //编写一个InvocationHandler类
class myInvocationHandler implements InvocationHandler{
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
// TODO Auto-generated method stub
return null;
}
}
//创建实例,接受一个invocationhandler对象
c.newInstance(new myInvocationHandler());

方式2,newProxyInstance这个方法需要三个参数,可以直接创建target的代理对象  

        Object proxy3 = Proxy.newProxyInstance(  

                target.getClass().getClassLoader(),  

                /*new Class[]{Collection.class},*/  

                  

                //获取target上的接口  

                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(method.getName() + " running time of " + (endTime - beginTime));  

                        return retVal;*/  

                          

                        //把上边的代码封装到一个类中,让后调用该类的方法,就实现了方法的封装  

                        advice.beforeMethod(method);  

                        Object retVal = method.invoke(target, args);  

                        advice.afterMethod(method);  

                        return retVal;                          
}  
});  

        return proxy3;  
}  

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息