您的位置:首页 > 职场人生

黑马程序员——Java学习笔记之⑧——“Java新技术”

2014-03-30 15:22 225 查看
----------- android培训java培训、期待与您交流! ------------

1、ide : itegrity developmentenvironment 集成开发环境
perspectiveview : 透视图

2、基本数据类型的自动装箱和拆箱:为了方便基础数据类型及其包装类的使用。在某些情况下无须人工地进行转换。
Integer iObj = 3; //将一个基本数据类型int自动装箱为一个Integer对象
System.out.println (iObj + 12); //自动拆箱

2、享元模式(flyweight):就是有很多个小的对象,它们有很多属性相同,把它们变成一个对象, 把那些不同的属性变成方法的参数,称之为外部状态, 把那些相同的属性称之为这个对象的内部状态。它使用共享物件,用来尽可能减少内存使用量以及分享资讯给尽可能多的相似物件。常见做法是把它们放在外部数据结构,当需要使用时再将它们传递给享元。具体示例,见“设计模式”总结日志。

3、在建立Integer对象的时候,是存在常量池概念的。如果要封装为Integer对象的int型值在-128~127之间,那么JVM会先到Integer对象常量池中查找,是否有相同值的Integer对象,如果常量池中已经存在具有相同值的Integer对象,那么就将新建立的Integer对象的地址指向常量池中具有相同值的那个对象,也就是说它们会变成同一个对象,这就是享元模式。当然,如果要建立的Integer对象的值不在-128~127的范围内,那么就直接建立该Integer对象。
示例如下:
Integer i1 = 8;

Integer i2 = 8;

Integer i3 = 240;

Integer i4 = 240;

System.out.println(i1 == i2);
//返回true

System.out.println(i3 == i4);
//返回false

4、枚举(Enum):本身就是一个类。一般情况下是不能创建enum类型的实例的(构造方法可以有,但必须私有)。枚举类型相当于自己定义一个数据类型,而这个数据类型的名字是自己起的,类型里面的内容也是自己定义的,当用到这个类型的变量时,只能输入已经定义好的内容,这样就可以防止其他程序员输入不符合规定的值。
枚举是一种特殊的类,其中的每个元素都是该类的一个实例对象。枚举元素必须位于枚举体中的最开始部分,因为初始化动作最先执行的。
在枚举元素的后面跟上一对括号,就表示创建这个元素指向的实际对象的时候,使用哪个构造函数
注:如果枚举中只有一个元素,就可以作为单例的实现方式。
枚举类的定义示例如下:



5、操作枚举类型对象的常用方法:
valueOf();//得到枚举常量对应的值
toString();//得到当前枚举常量的名称,可以被复写,是得到的结果更易读(与name()功能相同,优先使用toString() )
equals();//判断两个枚举常量是否相同
ordinal();//得到当前枚举常量的位置排行
getClass();//获取对象所属的类名
values();//返回一个存储该枚举类型中对象的数组
枚举类型对象的操作方法实例如下:



6、反射:就是把Java类中的各个成分映射成相应的Java类。(反射会导致程序性能严重下降)(反射的具体细节,见“反射”总结日记)

7、Class:各个类在内存中的字节码。(字节码:一个类被类加载器加载到内存中,占用一片存储空间,这个空间里面的内容就是类的字节码。不同的类的字节码不同)
对字节码的比较要用 == ,判断某个字节码是不是某种类型(类名.getType() == 类型名.class ),因为每种类型的字节码只有一份

8、Constructor类:代表字节码中的一个构造方法。
得到某个类的所有的构造方法:Constructor[]constructor =Class.forName("java.lang.String").getConstructor();
得到某一个构造方法:Constructorconstructor=Class.forName("java.lang.String").getConstructor(StringBuffer.class);//这里的StringBuffer.class是一个参数,如果要获取某个构造函数,只需加入对应的参数列表即可。
通过newInstance();方法建立一个对应构造方法的实例。

9、Method类:代表字节码的一个方法
MethodmethodCharAt= String.class.getMethod("charAt", int.class);//getMehod参数形式为:(方法名,参数类型的字节码文件)
Charch= methodCharAt.invoke(str1, 1);//invoke两个参数:第一个参数是具体调用该方法的对象,第二个参数是执行该方法的具体参数(如果有多个参数,就将这些参数封装为一个数组Object[],注意当接收多个int类型的参数时,要将其封装为Integer类型的数组,否则会发生异常。如果有多个相同类型的参数,也可以使用可变参数)。如果str1这个参数为null,那么就说明Method对象对应的是一个静态方法。也就是说如果如果方法时静态方法,那么使用invoke时,其第一个参数为null,因为不需要该方法所属类的实例对象存在,就能调用该方法。

10、Field类:代表字节码中的一个成员变量。得到的Field对象是对应到对象上的成员变量。
getField();//获取字节码文件中的公有成员变量,不包括私有变量
getDeclaredField();//获取字节码文件中的成员变量,包括私有变量
Field[]getFields();//获取字节码文件中所有的成员变量,不包括私有变量
setAccessible(true);//暴力反射,即获取私有对象变量的反射后,给予权限得以得到它的值
Field field.get(Object obj)//获取对象中obj中field变量的值

11、得到字节码对应实例对象的方法:
①通过“类名.class”的形式。(例:System.class )
②通过.getClass(),这需要已经存在了一个类的对象,通过getClass方法获取对象的字节码文件。(例:newDate().getClass() )
③Class.forName("类名"),通过静态方法去查询(首先在虚拟机中查找,如果存在就加载,如果不存在,就上硬盘中查询,并加载到虚拟机缓存中,并返回字节码文件)和加载对应类的字节码。(例:Class.forName("java.util.Date") )

12、Class9个预定义的基本类型:boolean, byte, char, short, int, long, float, double, (外加void)。可以通过isPrimitive(); 来判断是否为基本类型
可用:Boolean.TYPE,Character.TYPE, Byte.TYPE, Short.TYPE, Integer.TYPE,Long.TYPE, Float.TYPE,Double.TYPE, Void.TYPE 查看
总之,只要是在源程序中出现的类型,都有各自的Class实例对象,例如: int[] , void

13、 数组的反射:具有相同的元素类型和纬度的数组,其反射后的字节码文件是同一个。示例如下:
int[] a1 =newint[3];

int[] a2 = new int[4];
System.out.println(a1==a2); //false,因为a1和a2是两个不同的对象

System.out.println(a1.getClass() == a2.getClass()); //ture,因为其元素类型都为int,纬度都为一维。

14、asList( Object[] args);将数组转换为list集合
int[] a5 =newint[]{1,2,3};
Integer[] a6 =newInteger[]{1,2,3};

String[] a7 = new String[]{"a","b","c"};

System.out.println(a5);//[I@c971d55

System.out.println(a6);//[Ljava.lang.String;@1506bde8

//(jdk1.4中)asList(Object[]args),而String为Object,但int不是

System.out.println(Arrays.asList(a5));//[[I@c971d55]这里如果将a5中的元素封装为Integer类型的话,就会打印出a5集合中的元素,因为Integer是Object
System.out.println(Arrays.asList(a6));//[1,2,3]
System.out.println(Arrays.asList(a7));//[a,b,c]

15、数组反射的应用思路:将一个数组转化为对象obj-->用对象获取字节码文件,判断是否为数组Class-->是,使用Arrays工具类的Array.getLength(obj)获取长度,for循环一个个输出数组元素Array.get(obj,index); -->否,直接输出obj。

16、内存泄露:一般情况下,如果对象中复写了HashCode,则在对象pt存入HashSet集合后,如果修改了该对象的内容,这时其HashCode已经改变,pt已存储到了别的地方,如果执行删除pt的操作会失败。这就是内存泄露,即某个对象不用了,但是它一直在占用内存空间。

17、AOP(AspectOriented program,简称AOP)即为面向方面的编程。
系统中存在交叉业务,一个交叉业务就是要切入到系统中的一个方面。交叉业务的编程问题即为面向方面的编程(Aspect Oriented program,简称AOP),AOP的目标就是要使交叉业务模块化。可以采用将切面代码移动到原始方法的周围,这与直接在方法中编写切面代码的运行效果是一样的。使用代理技术正好可以解决这种问题,代理是实现AOP功能的核心和关键技术。

18、JavaBean是一种特殊的Java类,主要用于传递数据信息,这种java类中的方法主要用于访问私有的字段,且方法名称符合某种命名规则。
如果要在两个模块之间传递多个信息,可以将这些信息封装到一个JavaBean中,这种JavaBean的实例对象通常称之为值对象(Value Object,简称VO)。这些信息在类中用私有字段来存储,如果读取或设置这些字段的值,则需要通过一些相应的方法来访问。JavaBean的属性是根据其中的setter和getter方法来确定的,而不是根据其中的成员变量。如果方法名为setId,至于把它存在哪个变量上,不用管。如果方法名为getId,至于从哪个变量上取,不用管。去掉set或者get前缀后,剩余部分就是属性名,如果剩余部分的第二个字母是小写的,则把剩余部分的首字母改成小的。总之,一个类被当做JavaBean使用时,JavaBean的属性是根据方法名推断出来的,它根本看不到java类内部的成员变量。

19、JavaBean的好处:
①在Java EE开发中,经常要使用到JavaBean。很多环境就要求按JavaBean方式进行操作。
②JDK中提供了对JavaBean进行操作的一些API,这套API就称为内省(introSpector)。如果要自己通过getX方法来访问私有的x,有一定难度。用内省这套API操作JavaBean比用普通类的方式更方便。

20、使用beanutils工具包操作JavaBean:(需要自行下载,并导入工具包:org.apache.commons.beanutils)
①BeanUtils.setProperty(pt,String propertyName , StringpropertyValue); //将pt对象的propertyName的设置为propertyValue
②BeanUtils.getProperty( pt ,String propertyName ); //获取pt对象的propertyName属性的值,但是BeanUtils会自动进行类型转换。例如:
ReflectPoint pt = new ReflectPoint(3,5); //这里pt是一个JavaBean类(ReflectPoint)的对象
System.out.println(BeanUtils.getProperty(pt,"x").getClass().getName());打印结果为java.lang.String

③PropertyUtils.setProperty(pt,String propertyName, propertyValue);
④PropertyUtils.getProperty(pt , String propertyName );//获取pt对象的propertyName属性的值,这里PropertyUtils会自动匹配属性类型,且不会进行类型转换。例如:
System.out.println(PropertyUtils.getProperty(pt,"x").getClass().getName());打印结果为java.lang.Integer
上述两个工具包的操作实例如下:



21、PropertyDescriptor类:表示JavaBean类通过存储器导出一个属性。主要方法:
getPropertyType(),获得属性的Class对象。
getReadMethod(),获得用于读取属性值的方法;getWriteMethod(),获得用于写入属性值的方法。
hashCode(),获取对象的哈希值。
setReadMethod(Method readMethod),设置用于读取属性值的方法;setWriteMethod(MethodwriteMethod),设置用于写入属性值的方法;
简单的内省操作如下所示:
ReflectPoint pt = new ReflectPoint(3,5);
String propertyName = "x";
PropertyDescriptor pd =newPropertyDescriptor(propertyName,pt.getClass());//PropertyDescriptor 描述 Java Bean 通过一对存储器方法导出的一个属性
Method methodGetX =pd.getReadMethod();
Object retVal = methodGetX.invoke(pt1,null);

比较复杂的内省操作实例:
BeanInfo beanInfo =Introspector.getBeanInfo(pt1.getClass()); //在 Java Bean 上进行内省,了解其所有属性、公开的方法和事件。

PropertyDescriptor[] pds =beanInfo.getPropertyDescriptors(); //获得属性的描述

Object retVal = null;

for(PropertyDescriptor pd : pds) //采用遍历BeanInfo的方法,来查找、设置类的属性。

if(pd.getName().equals(propertyName))

{

Method methodGetX=pd.getReadMethod();//如果找打了以x为参数的方法,就可得到它的get方法

retVal = methodGetX.invoke(pt1);

break;

}

22、注解:相当于一种标记,在程序中加入了注解就等于打上了某种标记。没加,等于没有某种标记。(jdk1.5的新特性:枚举、注解)标记可以添加在 包,类,字段,方法、方法的参数以及局部变量上。
以后javac编译器,开发工具和其他程序可以用反射来了解自己的类即各种元素上有无何种标记。有什么标记就干相应的事。

23、常用的注解介绍:
@SuppressWarnings("deprecation") //这个注解是为了不让系统提示已过时的方法等。(deprecated 过时的)
@Override //标注为复写了父类中的方法。
@Deprecated //注释此方法已经过时了。对于新编写程序的人来说,是不推荐使用的意思。对老程序来说,是这个方法还可以使用,还有效的意思。

@Override 示例:
@Override //这里如果有复写标识:@Override,说明是要复写父类中的equals方法,如果参数不对,就不能算是复写

public boolean equals(Object obj)

{

..........

............

}

注:在HashSet集合中,在定义对象的hashCode方法和equals方法时如果没有复写equals方法或者在尝试复写时,参数列表不对,这就不能算是复写,从而在比较时,程序会调用父类中的equals方法。从而使得自己定义的equals方法没有任何意义。这是新手常犯的错误。实际上如果参数列表不同的话,就只能叫做重载,而不是复写。

24、元注解:即“注解的注解”。它的生命周期为:Java源文件—>class文件—>内存中的字节码
@Retention(RetentionPolicy.RUNTIME) //这里是指将AnnotationDemo注解保留到运行期间
在反射测试的问题中,在注解前面加上这三种注解之一:(@SuppressWarnings、@Deprecated、@Override 都对应着SOURCE阶段)
①RetentionPolicy.SOURCE--->java源文件
②RetentionPolicy.CLASS--->class文件(默认的)
③RetentionPolicy.RUNTIME--->内存中的字节码文件

25、注解的定义示例(定义了高级属性):
@Target({ElementType.METHOD,ElementType.TYPE})//在定义注解时,加上该注解的意思,是指正在定义的注解既可用于方法上,又可用于类上(此外,Target的属性值还有ElementType.FIELD,表示可用于)

public @interface AnnotationDemo {

String color() default"black"; //设置注解的属性color的默认值“black”

String value(); //没有设置注解属性的默认值

int[] arrayAttr() default {1,2,3}; //数组属性

Enum.TrafficLamp lamp() defaultEnum.TrafficLamp.RED; //枚举属性

MetaAnnotation annotationAttr()default@MetaAnnotation("zby"); //注解属性

}

26、注解的属性:当一个注解中有多个属性时,如果有一个属性有缺省值,则使用该注解的时候,可使用缺省值,从而不定义该属性。如果该注解中只有一个没有缺省值得属性,则如果其他属性都使用缺省值,而只定义该属性时,也可以不写属性名和=,只写属性值即可

27、注解的反射调用:
//AnnotationDemo为已经定义过的一个注解
//AnnotationTest为已经定义好的一个类,其中用到了注解AnnotationDemo
AnnotationDemo annotation =(AnnotationDemo)(AnnotationTest.class.getAnnotation(AnnotationDemo.class));
System.out.println(annotation);
System.out.println(annotation.color());//打印出AnnotationDemo的属性

28、泛型< >在通过编译器编译后,会自动去掉,以便不影响程序运行效率。通过以下例子加以说明:
ArrayList<String>collection = new ArrayList<String>();
ArrayList<Integer>collection2 = new ArrayList<Integer>();
System.out.println(collection.getClass()== collection2.getClass());//结果为“true”,这说明编译完后的字节码文件中没有泛型了,泛型只是提供给编译器使用的,这叫做去类型化。
这时可以想到,可以通过反射往集合中加入其它类型的元素,因为反射能跳过编译器的编译。
collection2.getClass().getMethod("add",Object.class).invoke(collection2, "abc");

29、泛型:是java 1.5中定义的一种新的数据类型,是一种参数化的类,也叫“类中类”,它是面向对象的扩展。通过泛型可以定义类型安全的数据类型,它的最显著应用就是创建集合类,可以约束集合类内的元素类型,java中比较常用的是Map<Key,Value>和Collection<T> 。
泛型的原理:泛型是提供给java编译器使用的可以限定集合中的输入类型,让编译器挡住源程序中的非法输入。

30、泛型的优点:
①使用泛型的性能高,不需要装箱和拆箱的操作
②类型安全。泛型集合对它所存储的对象做了类型的约束,在没有跳过编译器之前它是不允许非泛型集合所存储的数据类型添加到泛型集合中去的。

31、泛型的特点:
①参数化类型与原始类型兼容
Collection<String> c=newVector(); 参数化类型与原始类型的对象,编译器报告警告
Collection c=newVector<String>(); //原始类型可以引用一个参数化类型的对象,编译器报告警告
②参数化类型不考虑类型参数的继承性
Vector<Object> v=newVector<String>(); //错误,参数类型不能继承
③在创建数组实例时,数组的元素不能使用参数化的类型
Vector<Integer>vectorlist[]=new Vector<Integer>[10];//错误,数组的元素不能使用参数化类型
④泛型中的 ? 通配符
使用?通配符可以引用其它各种参数化的类型,使用?通配符定义的变量主要做引用 ,可以调用与参数化类型无关的方法,不能调用与参数化有关的方法。
publci voidtestCollection(Collection<?> c)
{
c.add("element"); //这样编译器会报错,添加元素与参数化类型有关
System.out.print(c.size()); //size方法与参数类型无关,不会报错
}
⑤泛型中?通配符的限定(限定通配符包括自己)
Vector<? extends Number>x = new Vector<Integer>(); //限定通配符的上界
注:定义泛型的时候可以定义多个上限,例如:<T extends Senalizable & cloneable>
Vector<? super Integer>y = new Vector<Number>(); //限定通配符的下界

32、泛型的定义,示例如下:
public static <T> voidswapArr(T[] a, int i, int j) //定义一个交换数组中两个元素位置的泛型方法

{

T temp = a[i];

a[i] = a[j];

a[j] = temp;

}
// swapArr(new int[]{1,2,3,4,5,6},3,5); //错误,因为只有引用类型才能作为泛型方法的实际参数

// swapArr(newInteger[]{1,2,3,4,5,6},3,5) //正确,因为这里将int型数组中的元素封装成为了Integer对象

33、泛型的使用与通配符使用的比较
例子1:
//打印任意类型的集合(用通配符的方法)

public static voidprintCollection(Collection<?> collection){
System.out.println(collection.size());

for(Object obj : collection)
{

System.out.println(obj);

}}

例子2:
//打印任意类型的集合(用自定泛型的方法)

public static <T> voidprintCollection_2(Collection<T> collection){

System.out.println(collection.size());

for(Object obj : collection)
{

System.out.println(obj);

}}

这种情况下,通配符的方法比泛型的方法更有效。假如函数中还要进行添加操作,即:collection.add(T t),这时,泛型方法就比通配符方法更有效。
一般情况下,当一个类型变量用来表达两个参数之间或者参数和返回值之间的关系时,即同一个类型变量在方法签名的两处被使用,或者类型变量在方法体代码中也被使用,而不是仅在签名的时候使用,才需要使用泛型方法。如果类中只有一个方法需要使用泛型,要使用类级别的泛型,而不是方法级别的泛型

34、Dao:data access objet 数据连接对象

35、泛型类中不能定义静态方法,当然,如果类中某个方法跟泛型类中的泛型不同的话,可以为静态。

36、类加载器(ClassLoader):本身也是个Java类,被其他类加载器加载,而位于源头的类加载器是BootStrap。BootStrap类加载器不需要被别的类加载器加载,因为它是嵌套在java虚拟机的内核中的,随着虚拟机的启动而加载。
通过getClassLoader(); 可以得到一个类的类加载器。由于类加载器也是一个java类。因此,接着可以用getClass().getName()来得到该加载器的名称。示例如下;
String classLoader =System.class.getClassLoader().getClass().getName() ; //语句执行后,classLoader的内容为null,这说明,System类的类加载器是BootStrap。
当然,当获得一个类加载器后,还可以用getParent(); 获得此类加载器的父类加载器。

37、Java虚拟机中可以安装多个类加载器,系统默认有三个主要加载器,负责加载特定位置的类:(其结构体系如下)

38、类加载器的委托机制:每个类加载器加载类时,要先委托给上级类加载器。

39、JVM可以在运行期动态生成出类的字节码,这种动态生成的类往往被用作代理类,即动态代理类。

40、JVM生成的动态类必须实现一个或者多个接口,所以JVM生成的动态类只能用作具有相同接口的目标类的代理。

41、CGLIB库可以动态生成一个类的子类,一个类的子类也可以用作该类的代理,所以,如果要为一个没有实现接口的类生成动态代理类,那么可以使用CGLIB库。

42、应用AOP时,系统功能代码可插入的位置,实例如下:



43、获取一个类的动态代理实例的应用示例如下:





----------- android培训java培训、期待与您交流! ------------
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: