----------- android培训、java培训、java学习型技术博客、期待与您交流! ------------
《一》 枚举
枚举也是一种类,只是比较特别,它将所有的有限个实例对象放在它的内部,你可以通过“枚举名.枚举实例”来访问它的实例对象。使用的时候:当你用到某个类,而且它只有有限个实例对象,它的类型不确定很抽象的时候,你可以考虑将它定义成枚举类,如红绿灯,季节等。
Java 中的枚举类型采用关键字enum 来定义,从jdk1.5才有的新类型,所有的枚举类型都是继承自Enum 类型。
使用方式:
public enum Light {
/* 枚举也可以象一般的类一样添加方法和属性,你可以为它添加静态和非静态的属性或方法,这一切都象你在一般的类中做的那样. */
// 利用构造函数传参,枚举元素必须写在最前面,否则编译出错,且每个枚举元素的写法要与当前构造方法匹配。
RED (1), GREEN (3), YELLOW (2);
private int nCode ;
//构造器默认只能是private, 从而保证构造函数只能在内部使用
private Light( int _nCode) {
this . nCode = _nCode;
}
}
枚举类型是一种类型,用于定义变量,以限制变量的赋值,赋值时通过"枚举名.值"来取得相关枚举中的值,你也可以在枚举类的内部定义一个抽象方法,只是你的枚举元素(实例对象)必须以匿名内部类的形式将该抽象方法实现了。
枚举类的常用方法:
(1) ordinal()方法: 返回枚举值在枚举类种的顺序。这个顺序根据枚举值声明的顺序而定。
(2) compareTo()方法: Enum实现了java.lang.Comparable接口,因此可以比较与指定对象的顺序。Enum中的compareTo返回的是两个枚举值的顺序之差。当然,前提是两个枚举值必须属于同一个枚举类,否则会抛出ClassCastException()异常。
(3) values()方法: 静态方法,返回一个包含全部枚举值的数组。
(4) toString()方法: 返回枚举常量的名称。
(5) valueOf(Class<T> enumType, String name)方法: 这个方法和toString方法是相对应的,返回带指定名称的指定枚举类型的枚举常量。
(6) equals()方法: 比较两个枚举类对象的引用。
《二》反射
我的理解是,反射是对java里各种类的重新包装和操作,反射提供了操作各种类的成员变量,成员方法,构造方法,的类,比如Field,Method,Constructor,Package等等。可以分别操作类的成员变量,成员方法,构造方法,包等等。
Class类 :注意与关键字class是不同的,Java程序中的各个Java类属于同一类事物,描述这类事物的Java类名就是Class类。
Class类的对象对应各个类在内存中的字节码,例如:Person类的字节码,ArrayList类的的字节码等等。
字节码:java是通过编译源文件.java文件成class文件(字节码文件),再加载到内存中进行处理。被加载到内存中的字节码也对应着一个对象,这个对象的类型就是Class类。
Class类实例对象的获取方式:
类名.class | 对象.getClass() | Class.forName(“类名”)
比如:
String str1=”abc”;
Class cls1=str1.getClass();
Class cls2=String.class ;
Class cls3= Class.forName(”java.lang.String”);
其中,第三种方式表示加载类名所对应的类的字节码,并返回该类对应的Class对象。
注意:由于java的数据共享特性,获取的实例对象有可能都是统一个字节码文件。
判断方法:isPrimitive():用于判断8个基本类型 + void关键字
注意:9种预定义类型各对应的一个包装类,每个包装类中有个常量字段TYPE,分别表示该包装类对应基本类型的Class对象,即:int.class == Integer.TYPE为true。
Constructor类代表某个类中的一个构造方法
得到某个类所有的构造方法:
Constructor[]constructors=Class.forName("java.lang.String").getConstructor();
得到某个类某一个构造方法:
Constructorconstructor=Class.forName("java.lang.String").getConstructor(StringBuffer.class);
创建实例对象:
通常方式:String str = new String(new StringBuffer("abc"));反射方式:
String str=(String)constructor.newInstance(newStringBuffer("abc"));
Method类代表某个类中的一个成员方法
得到类中的某一个方法:
Method
charAt= Class.forName("java.lang.String").getMethod("charAt",int.class);
通常方式:str.charAt(1);
反射方式:charAt.invoke(str,1);
如果传递给Method对象的invoke()方法的第一个参数为null,这没有什么意义,说明该Method对象对应的是一个静态方法。
Field类代表某个类中的一个成员变量
得到的Field对象是对应到类上面的成员变量。原因:类只有一个,而该类的实例对象有多个,如果是与对象关联,那关联的是哪个对象呢?所以字段fieldX代表的是x的定义,而不是具体的x变量。
数组的反射:
1.具有相同维数和元素类型的数组属于同一个类型,即具有相同的Class实例对象。
2.代表数组的Class实例对象的getSuperclass()方法返回的父类为Object类对应的Class.
3.基本类型的一维数组可以被当作Object类型使用,不能当作Object[]类型使用;非基本类型的一维数组,既可以当做Object类型使用,又可以当做Object[]类型使用。
4.Arrays.asList()方法处理int[]和String[]时的差异。
Arrays工具类用于完成对数组的反射操作。
《三》泛型
泛型:JDK1.5版本以后出现新特性。用于解决安全问题,是一个类型安全机制。好处
1.将运行时期出现问题ClassCastException,转移到了编译时期。,
方便于程序员解决问题。让运行时问题减少,安全。,
2,避免了强制转换麻烦。
泛型格式:通过<>来定义要操作的引用数据类型。
在使用java提供的对象时,什么时候写泛型呢?
通常在集合框架中很常见,
只要见到<>就要定义泛型。
其实<> 就是用来接收类型的。
当使用集合时,将集合中要存储的数据类型作为参数传递到<>中即可。
ArrayList<String> al=new ArrayList<String> ();
al.add("1");
al.add("2");
al.add("3");
al.add("4");
Iterator<String> it=al.iterator();
while(it.hasNext())
{
String s= it.next();
System.out.println(s+" ");
}
泛型类定义的泛型,在整个类中有效。如果被方法使用,
那么泛型类的对象明确要操作的具体类型后,所有要操作的类型就已经固定了。
为了让不同方法可以操作不同类型,而且类型还不确定。
那么可以将泛型定义在方法上。
特殊之处:
静态方法不可以访问类上定义的泛型。
如果静态方法操作的应用数据类型不确定,可以将泛型定义在方法上。
class Tool <T>
{
private T t ;
public T getT() {
return t;
}
public void setT(T t) {
this.t = t;
}
//在方法上定义的泛型,适用于方法中
public<Q> void show (Q q)
{
System.out.println("show"+q );
}
public static<Q> void print (Q q)
{
System.out.println("print"+q);
}}
//接口上的泛型
interface Inter <T>
{
public void show (T t);
}
class InterImpl<T> implements Inter<T>
{
public void show(T t)
{
System.out.println("show:"+t);
}
}
class InterIm implements Inter<String>
{
public void show(String t)
{
System.out.println("show:"+t);
}}
总结:
1.类上定义的泛型,适合整个类中对该泛型的使用
2.方法上定义的泛型,用于该方法上,这样泛型就可以操作与类不同的泛型
3.静态方法定义的泛型,如同2中使用,但该静态方法不可以使用类定义的泛型,因为类定义的泛型是在实例化对象时产生的,不是类载入时就有的。
《四》类加载器
用来加载 Java类到 Java 虚拟机中。一般来说,Java虚拟机使用 Java类的方式如下:Java 源程序(.java文件)在经过 Java 编译器编译之后就被转换成 Java字节代码(.class 文件)。类加载器负责读取 Java字节代码,并转换成 java.lang.Class类的一个实例。每个这样的实例用来表示一个 Java类。通过此实例的newInstance()方法就可以
注意:
1.java虚拟机中可以安装多个类加载器,系统默认三个主要类加载器,每个类负责加载特定位置的类:BootStrap,ExtClassLoader , AppClassLoader
2.类加载器也是java类,因为其他是java类的类加载器本身也要被类加载器加载,显然必须有第一个类加载器不是java类,这就是BootStrap(它是用C++编写的)
3.java虚拟机中的所有类装载器采用具有父子关系的树形结构进行组织,在实例化每个类加载器对象时,需要为其指定一个父级类装载器对象或者默认采用系统类装载器为其父级类加载。
类加载器优先级:BootStrap > ExtClassLoader > AppClassLoader
类加载器的树状组织结构
Java中的类加载器大致可以分成两类,一类是系统提供的,另外一类则是由 Java应用开发人员编写的。
系统提供的类加载器主要有下面三个:
引导类加载器(bootstrap class loader):它用来加载 Java 的核心库,是用原生代码来实现的,并不继承自java.lang.ClassLoader。
扩展类加载器(extensions class loader):它用来加载 Java 的扩展库。Java虚拟机的实现会提供一个扩展库目录。该类加载器在此目录里面查找并加载 Java类。
系统类加载器(system class loader):它根据Java 应用的类路径(CLASSPATH)来加载 Java 类。一般来说,Java应用的类都是由它来完成加载的。可以通过ClassLoader.getSystemClassLoader()来获取它。
除了系统提供的类加载器以外,开发人员可以通过继承java.lang.ClassLoader类的方式实现自己的类加载器,以满足一些特殊的需求。
除了引导类加载器之外,所有的类加载器都有一个父类加载器。通过getParent()方法可以得到。对于系统提供的类加载器来说,系统类加载器的父类加载器是扩展类加载器,而扩展类加载器的父类加载器是引导类加载器;对于开发人员编写的类加载器来说,其父类加载器是加载此类加载器 Java 类的类加载器。因为类加载器 Java类如同其它的 Java类一样,也是要由类加载器来加载的。一般来说,开发人员编写的类加载器的父类加载器是系统类加载器。类加载器通过这种方式组织起来,形成树状结构。树的根节点就是引导类加载器。
创建出该类的一个对象。
类加载器的委托加载机制:
1.当java虚拟机要加载一个类时,到底派出哪个类加载器去加载呢?
首先当前线程的类加载器去加载线程中的第一个类,如果类A中引用了类B,java虚拟机将使用加载类A的加载器来加载类B,还可以直接调用ClassLoader.loadClass()方法来指定某个类加载器去加载某个类。
2.每个类加载器加载类时,又先委托给其上级类加载器。
当所有祖宗类加载器没有加载到类时,回到发起者类加载器,还加载不了,则抛出ClassNotFoundException,不是再去找发起者类加载器的儿子,因为没有getChild方法
《五》动态代理技术
为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不想或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。代理模式(Proxy Pattern),是23种java常用设计模式之一,属于结构型模式。1.远程代理(RemoteProxy)为一个对象在不同的地址空间提供局部代表。
2.虚代理(VirtualProxy)根据需要创建开销很大的对象。
3.保护代理(ProtectionProxy)控制对原始对象的访问。
4.智能指引(SmartReference)取代了简单的指针,它在访问对象时执行一些附加操作。
使用时候:假设有一组对象都实现同一个接口,实现同样的方法,但这组对象中有一部分对象需要有单独的方法,传统的办法是在每一个应用端都加上这个单独的方法,但是代码重用性低,耦合性高。如果用代理的方法则很好的解决了这个问题。
Java动态代理类位于Java.lang.reflect包下,一般主要涉及到以下两个类:
(1) Interface InvocationHandler:该接口中仅定义了一个方法Object:invoke(Object obj,Method method, Object[] args)。在实际使用时,第一个参数obj一般是指代理类,method是被代理的方法, args为该方法的参数数组。这个抽象方法在代理类中动态实现。
(2)Proxy:该类即为动态代理类,其中主要包含以下内容:
Protected Proxy(InvocationHandler h):构造函数,用于给内部的h赋值。
Static Class getProxyClass (ClassLoader loader, Class[] interfaces):获得一个代理类,其中loader是类加载器,interfaces是真实类所拥有的全部接口的数组。
Static Object newProxyInstance(ClassLoader loader, Class[] interfaces,InvocationHandler h):返回代理类的一个实例,返回后的代理类可以当作被代理类使用(可使用被代理类的在Subject接口中声明过的方法)。
所谓Dynamic Proxy是这样一种class:它是在运行时生成的class,在生成它时你必须提供一组interface给它,然后该class就宣称它实现了这些interface。你当然可以把该class的实例当作这些interface中的任何一个来用。当然啦,这个Dynamic Proxy其实就是一个Proxy,它不会替你作实质性的工作,在生成它的实例时你必须提供一个handler,由它接管实际的工作。
----------- android培训、java培训、java学习型技术博客、期待与您交流! ------------