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

黑马程序员---Java高新技术学习笔记(后篇)

2013-11-06 14:15 477 查看
------------Android培训、Java培训、期待与您交流----------

1.注解

相当于一种标记,在程序中加了注解就等于为程序打上了某种标记,之后java编译器开发工具和其他程序可以用反射的方式来了解你的类及各种元素上有无何种标记,看你有什么标记就去干相应的事,标记可以加在包,类,字段,方法方法的参数以及局部变量上。注解的属性:一个注解相当于一个胸牌,其中加入各种属性加以区分。

@ITAnnotation(color = "red",value = "abc",arrayAttr={1,2,3})//如果数组arrayAttr只有一个值的话
//可以简写成arrayAttr=1
@JavaEnhanceAnnotation(String={"abc","def","ghi","jkl"} , num = 5)
public class AnnotationTest {
//注解的应用
@SuppressWarnings("deprecation")
//如果只有value属性需要设置,可以不写"value ="字段
@ITAnnotation("uvwxyz")
public static void main(String[] args) throws Exception
{
System.runFinalizersOnExit(true);//方法过时
if(AnnotationTest.class.isAnnotationPresent(ITAnnotation.class))
{

ITAnnotation annotationTest =
(ITAnnotation)AnnotationTest.class.getAnnotation(ITAnnotation.class);
System.out.println(annotationTest.color());
System.out.println(annotationTest.value());
System.out.println(annotationTest.arrayAttr().length);
}
if(AnnotationTest.class.isAnnotationPresent(JavaEnhanceAnnotation.class))
{
JavaEnhanceAnnotation annotationTest =
(JavaEnhanceAnnotation)AnnotationTest.class.getAnnotation(JavaEnhanceAnnotation.class);
System.out.println(annotationTest.String().length);
System.out.println(annotationTest.num());
System.out.println(annotationTest.lamp().nextLamp().name());
}
}

@Deprecated
public static void sayHola()
{
System.out.println("lalala");
}

}


元注解

根据放射测试的问题,引出@Retention(枚举类型)的三种取值:

1.RetentionPolicy.SOURCE-->java源文件

2.RetentionPolicy.CLASS-->class文件

3.RetentionPolicy.RUNTIME-->内存中的字节码

import java.lang.annotation.*;

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD,ElementType.TYPE})
//Target表明注解只能放在方法以及类,接口或枚举类型的上方,别的地方无效
public @interface ITAnnotation
{
//定义基本类型的属相和应用属性
String color() default "blue";//设置ITAnnotation中的color为缺省属性
String value();
int[] arrayAttr() default {3,4,5};
}


2.泛型

它是提供给javac编译器使用的,可以限定集合中的输入类型,让编译器挡住源程序中的非法输入

编译器编译带类型说明的集合时会去除掉"类型信息",使程序运行效率不收影响,对于参数化的泛型类型

getClass()方法的返回值和原始类型完全一样,由于编译生成的字节码会去掉泛型的类型信息,只要能跳过

编译器,就可以通过反射的方法往某个泛型集合中加入其他类型的数据。

ArrayList<E>类定义和ArrayList<Integer>类引用中涉及如下术语:

1.整个称为ArrayList<E>泛型类型

2.ArrayList<E>中的E称为类型变量或者类型参数

3.整个ArrayList<Integer>称为参数化的类型

4.ArrayList<Integer>中的Integer称为类型参数的实例或实际类型参数

5.ArrayList<Integer>中的<>读typeof

6.ArrayList称为原始类型

参数化类型与原始类型的兼容性

1.参数化类型可以引用一个原始类型的对象,编译报告警告
Collection<String> c = new Vector();

2.原始类型可以引用一个参数化类型的对象,编译报告警告
Collection c = new Vector<String>();
3.参数化类型不考虑类型参数的继承关系

 1.Vector<String> v = new Vector<Object>();错误,不写<Object>不会出现错误

 2.Vector<Object> v = new Vector<String>();错误

 

4.在创建数组实例时,数组的元素不能使用参数化的类型

Vector<Integer> vectorList[] = new Vector<integer>[10];

 

Vector v1 = new Vector<String>();对

Vector<Object> v = v1;对

Vector<Object> v =new Vector<String>();错

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.Vector;

import com.intel.day01.ReflectPoint;

public class GenericTest
{
public static void main(String[] args) throws Exception
{
ArrayList collection1 = new ArrayList();
collection1.add(1);
collection1.add(1L);
collection1.add("abc");
//int i = (Integer)collection1.get(1);
//System.out.println(i);

/*================================华丽的分割线====================================*/

ArrayList<String> collection2 = new ArrayList<String>();
collection2.add("abc");
String element = collection2.get(0);
System.out.println(element);

/*================================华丽的分割线====================================*/

//泛型的应用省去了类型转换之苦
Constructor<String> cons = String.class.getConstructor(StringBuffer.class);
String strr = cons.newInstance(new StringBuffer("abcd"));
System.out.println("Generic:"+strr.charAt(2));

/*================================华丽的分割线====================================*/

ArrayList<Integer> collection3 = new ArrayList<Integer>();
System.out.println(collection3.getClass() == collection2.getClass());
//collection3.add("abcde");
collection3.getClass().getMethod("add", Object.class).invoke(collection3, "abcde");
System.out.println("Reflect:"+collection3.get(0));
//此代码说明泛型的定义是给编译器看的,如果按普通的add添加方法,编译无法通过。
//但是用反射的方法,就可以跳过编译器,忽略了泛型的字节码,便可以添加其他类型的参数。

/*================================华丽的分割线====================================*/

//泛型中的 ? 通配符的应用和扩展,详见方法
printCollection(collection1);

/*================================华丽的分割线====================================*/

//泛型&迭代==》输出集合中的键和值
HashMap<String,Integer> maps = new HashMap<String, Integer>();
maps.put("zxx",28);
maps.put("xxx",27);
maps.put("zzz",26);

Set<Map.Entry<String,Integer>> entrySet = maps.entrySet();
for(Map.Entry<String,Integer> entry : entrySet)
{
System.out.println(entry.getKey() + ":" + entry.getValue());
}

/*================================华丽的分割线====================================*/

//自定义反省类型及其应用
add(1,2);
add(2.3 , 5);
add(3 , "abc");
add('c' , 1L);

/*================================华丽的分割线====================================*/

swap(new String[]{"12","23","34"},1,2);
//swap(new int[]{1,3,5,2,4},2,4);<T>不能为基本数据类型,必须是引用类型

/*================================华丽的分割线====================================*/

//DAO Data Access Object数据访问对象--->用于增删改查(C.R.U.D.)
GenericDao<ReflectPoint> dao = new GenericDao<ReflectPoint>();
dao.add(new ReflectPoint(3, 3));
//dao.findById(0);
//dao.findByUserName("str");
//dao.findByConditions("string");

/*================================华丽的分割线====================================*/

//通过反射获得泛型的实际参数类型
//Vector<Date> v = new Vector<Date>();
//System.out.println(v.getClass().getName());无法得到v的参数类型
Method applyMethod = GenericTest.class.getMethod("applyVector", Vector.class);
Type[] types = applyMethod.getGenericParameterTypes();
ParameterizedType pType = (ParameterizedType)types[0];
System.out.println(pType.getRawType().toString());//打印原始类型
System.out.println(pType.getActualTypeArguments()[0]);
}

private static <T> void swap(T[] a , int i , int j)
{
T tmp = a[i];
a[i] = a[j];
a[j] = tmp;
}

public static void printCollection(Collection<?> collection)
{
//collection.add("1234");错误:因为他不知自己未来匹配的一定就是String类型
//collection = new HashSet<Date>();//正确,因为用问号通配符定义的参数,可以指向任何类型的集合
System.out.println("??:"+collection.size());//正确,此方法与参数类型无关
for(Object col : collection)
{
System.out.println("?:"+col+"<>"+col.getClass().getName());
}

/*
* 限定通配符总是包括自己
限定通配符的上界:通配符仅可以匹配Number和Number的子类
Vector<? extends Number> x = new Vector<Integer>();//Y
Vector<? extends Number> y = new Vector<String>();//N
限定通配符的下界:通配符可以匹配的最低类型为integer,只能向上匹配
Vector<? super Integer> x = new Vector<Number>();//Y
Vector<? super Integer> x = new Vector<Byte>();//N虽然byte和integer是平级但是不行
*/
}

private static <T> T add(T x , T y)
{
//return x + y;报错的原因是因为两个参数的类型不一定可以进行加法运算
return null;
}

public static void applyVector(Vector<Date> v)
{
System.out.println("通过反射获得泛型的实际参数类型");
}
}


3.类加载器

调用方法是需要用到的类,都需要通过类加载器加载进来

Java虚拟机中可以安装多个类加载器,系统默认有三个主要的类加载器,

每个类加载器负责加载特定位置的类:

BootStrap ExtClassLoader AppClassLoader

类加载器也是Java类,所以其本身也要被类加载器加载,显然必须有一个非java类的加载器BootStrap

JVM中的所以类加载器采用具有父子关系的的树形结构进行组织,在实例化每个类加载器对象时,需要

为其指定一个父级类加载器对象或者默认采用系统类加载器为其父级类加载

 

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

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

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

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

委托加载机制

每个类加载器加载类时,又先委托给其实上级类加载器,如果父级加载器已经将该类加载,则直接使用

避免了重复加载,占用内存资源

 1.当所有父级类加载器没有加载到类,回到发起者类加载器,还加载不了的话,则只能抛出
ClassNotFoundExceptipon,而不是再去找发起者类加载器的子级,因为没有getChild方法
即使有该方法,那么多儿子,也不知道该找哪一个

import java.util.Date;

public class ClassLoaderTest extends ClassLoader
{
public static void main(String[] args) throws Exception
{
System.out.println(ClassLoaderTest.class.getClassLoader().getClass().getName());
//sun.misc.Launcher$AppClassLoader说明ClassLoader类是由AppClassLoader加载的
System.out.println(System.class.getClassLoader());
//null说明System类是由BootStrap加载的

ClassLoader loader = ClassLoaderTest.class.getClassLoader();
while(loader!=null)
{
System.out.println(loader.getClass().getName());
loader = loader.getParent();
}
System.out.println(loader+" --> $BootStrap");
/*
sun.misc.Launcher$AppClassLoader
sun.misc.Launcher$ExtClassLoader
null --> $BootStrap
*/

//System.out.println(new ClassLoaderAttachment().toString());
/*
* 打印结果-->Hola Maria...
* 如果将intellib中的加过密的class文件吧bin中正常的class文件替换掉则会出现错误
Exception in thread "main" java.lang.ClassFormatError: Incompatible magic
value 889275713 in class file com/intel/day02/ClassLoaderAttachment
出现此情况下,必须用自己定义的类加载器进行解密,前提需要继承ClassLoader类
覆盖其findClass方法,详见MyClassLoader.java
*/
//打印加密后的ClassLoaderAttachment.class文件
Class clazz = new MyClassLoader("intellib").loadClass("ClassLoaderAttachment");
Date d1 = (Date)clazz.newInstance();
System.out.println(d1);
}
}

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