一、静态导入
import static java.lang.Math.max; //导入莫个静态方法。
import static java.lang.Math.*; //导入所有类中的静态方法
二、可变参数:public void method(int x, int y, int...args){ }
只能出现在参数类表最后。
....在类型与变量名之间 有无空格都可以。
用数组的方式进行调用。
三、for循环增强
for(type 变量名:集合变量名){…………}
例 for( int arg:args){
sum += arg;
}
变量类型前可以加修饰符 如加上final的局部变量可以被内部类访问。
可迭代的集合必须实现Iterable接口。
基本数据类型的自动拆装箱
Integer i = 78; Integer i1=3; 128
Integer i2=3; 128
i1==i2 true false;
享元模式 (小整数 -128--127)
对象很小时又经常使用 共同属性抽出来作为内部特性,经常变化的作为外部的属性当做方法的参数传入。
四、枚举
枚举:就是要让某个类型的变量的取值只能为若干个固定值中的一个,否则,编译器就报错
①枚举的基本应用
public enum WeekDay{
SUN,MON,TUE,WED,THI,FRI,SAT;
}
WeekDay weekDay = WeekDay.FRI;
System.out.println(weekDay);
System.out.println(weekDay.name());
System.out.println(weekDay.ordinal());//排行
System.out.println(WeekDay.valueOf("SUN").toString());//转换为枚举元素
System.out.println(WeekDay.values().length);//把枚举元素放到数组
②带有构造方法的枚举
public enum WeekDay{
SUN(1),MON(),TUE,WED,THI,FRI,SAT;
private WeekDay(){System.out.println
("first");}
private WeekDay(int day)
{System.out.println("second");}
③带有抽象方法的枚举
public enum TrafficLamp{
RED(30){
public TrafficLamp nextLamp(){
return GREEN;
}
},
GREEN(45){
public TrafficLamp nextLamp(){
return YELLOW;
}
},
YELLOW(5){
public TrafficLamp nextLamp(){
return RED;
}
};
public abstract TrafficLamp nextLamp();
private int time;
private TrafficLamp(int time){this.time =
time;}
}
五、反射
Class类:描述所有java类的类
反射:反射技术把java类中的各种成分映射成相应的java类
java类的Class类显然提供一系列方法来获取其中的变量,方法,构造方法,修饰符,包等信息,这些信息就是用应用类的实例对象来表示,,它们是Field Mothed Contructor Package等
一个类中的每个成员都可以用相应的反射API类的一个实例对象来表示,通过调用Class类的方法可以得到这些实例对象后,有什么用,怎么用,这正是学习和应用反射的要点。
①构造方法的反射应用
Constructor constructor1 = String.class.getConstructor(StringBuffer.class);
String str2 = (String)constructor1.newInstance(new StringBuffer("abc"));
System.out.println(str2.charAt(2));
②成员变量的反射
ReflectPoint pt1 = new ReflectPoint(3,5);
Field fieldY = pt1.getClass().getField("y");
System.out.println(fieldY.get(pt1));
③获取私有的成员变量:
Field fieldX = pt1.getClass().getDeclaredField("x");//看得到却取不到
fieldX.setAccessible(true);//暴力反射
System.out.println(fieldX.get(pt1));
④成员变量反射的综合案例
将任意一个对象中的所有String类型的成员变量所对应的字符串的
“b”改成“a”:
private static void changeStringValue(Object obj) throws Exception {
Field[] fields = obj.getClass().getFields();
for(Field field : fields){
//if(field.getType().equals(String.class)){
if(field.getType() == String.class){
String oldValue = (String)field.get(obj);
String newValue = oldValue.replace('b', 'a');
field.set(obj, newValue);
⑤对接收数组参数的成员方法进行反射
我为什么用反射的方式调:我写程序的时候并不知道这个类,但是到我运行的时候可以通过传递参数的方式调用这类
String startingClassName = args[0];
Method mainMethod = Class.forName(startingClassName).getMethod("main", String[].class);
//mainMethod.invoke(null, new Object[]{new String[]{"111","222","333"}});
mainMethod.invoke(null, (Object)new String[]{"111","222","333"});
六、ArrayList_HashSet的比较及Hashcode分析
HashSet就是采用哈希算法存储对象的集合,它内部采用对某个数字进行取余的方式对哈希码进行分组和划分对象的存储区域。object类中定义了一个hashCode()方法来返回每个对象的哈希码
,当从HashSet集合中查找某个对象时,java系统首先调用对象的hashCode()方法获取该对象的哈希码,然后根据哈希码找到相应存储区域,最后取出该区域的每个元素与该对象进行equals方
法比较,这样就不用遍历整个集合就可以得到结论。
当一个对象被存储进HashSet集合中以后,就不能修改这个对象中的那些参与计算哈希值的字段了,否则,对象修改后的哈希值与最初存储进HashSet集合中的哈希值就不同了,这样就无法
找到该对象,这也导致无法从HashSet中单独删除当前对象,从而造成内存泄漏。
七、内省--JavaBean
内省主要用于JavaBean的操作
introSpector->JavaBean->特殊的java类,其方法符合某种特殊规则
JavaBean是一种特殊的java类,主要用于传递数据信息,这种java类中的方法主要用于访问私有的字段,且方法名符合某种命名规则。
如果要在两个模块之间传递多个信息,可以将这些信息封装到一个JavaBean中,这种JavaBean的实例对象称之为值对象(Value Object,简称VO)。目的只是传递值,动作方法就没了,这些
信息在类中用私有字段存储,如果读取或设置这些字段的值,则需要通过一些相应的方法来访问,JavaBean的属性是根据setter和getter方法来确定的。如方法名为getId,中文意思即为获取
id,至于你从哪个变量取,不要管。去掉前缀剩余的就是属性名,
如果第二个字母为少写,则把首字母改成小的。
①对JavaBean的简单内省操作
一个符合JavaBean特点的类可以当作普通类来处理,也可以当作JavaBean来操作。
jdk中提供了对JavaBean进行操作的一些API,这套API就称为内省。
②对JavaBean的复杂内省操作
get:
PropertyDescriptor pd = new PropertyDescriptor(propertyName,pt1.getClass());
Method methodGetX = pd.getReadMethod();
Object retVal = methodGetX.invoke(pt1);
set:
PropertyDescriptor pd2 = new PropertyDescriptor(propertyName,pt1.getClass());
Method methodSetX = pd2.getWriteMethod();
methodSetX.invoke(pt1,value);
复杂的get:
BeanInfo beanInfo = Introspector.getBeanInfo(pt1.getClass());
PropertyDescriptor[] pds = beanInfo.getPropertyDescriptors();
Object retVal = null;
for(PropertyDescriptor pd : pds){
if(pd.getName().equals(propertyName))
{
Method methodGetX = pd.getReadMethod();
retVal = methodGetX.invoke(pt1);
break;
}
}
return retVal;
八、注解及其应用
注解就是用于告诉开发工具或者是编译器,向它传递某种信息。
一个注解就是一个类。
注解相当于一种标记,标记可以加在包,类,字段,方法的参数已经局部变量上。
jdk自带的三个注解:@SuppressWarnings(去除警告) @Deprecated(添加警告) @Override(复写)
①为注解增加各种属性
public @interface ItcastAnnotation {
String color() default "blue";
String value();//
int[] arrayAttr() default {3,4,4};//数组类型属性
EnumTest.TrafficLamp lamp() default EnumTest.TrafficLamp.RED;//枚举属性
MetaAnnotation annotationAttr() default @MetaAnnotation("lhm");//注释类型属性
}
②注解的应用:
@ItcastAnnotation(annotationAttr=@MetaAnnotation("flx"),color="red",value="abc",arrayAttr=1)
class AnnotationTest{}
调用:
if(AnnotationTest.class.isAnnotationPresent(ItcastAnnotation.class)){
ItcastAnnotation annotation =
(ItcastAnnotation)AnnotationTest.class.getAnnotation(ItcastAnnotation.class);
System.out.println(annotation.color());
System.out.println(annotation.value());
System.out.println(annotation.arrayAttr().length);
System.out.println(annotation.lamp().nextLamp().name());
System.out.println(annotation.annotationAttr().value());
}
九、泛型
泛型应用 ArrayList后加<String>说明这个是String类型的
ArrayList<String> collection2=new ArrayList<String>();
collection2.add("abc");
STring element=collection2.get(1); //不用类型转换了
总结:没用泛型时,不管什么类型的对象都可以存储进同个集合,使用泛型集合可以将集合的元素限定为特殊类型,这样更安全,同时获取它时不需要对对象进行强制类型转换
泛型的通配符扩展应用
<? > 使用?通配符可以引用其他各种参数化类型,?通配符主要是作为引用,可以调用参数无关的方法,不能调用参数化有关的方法
collection.size()
<? extends >?通配符的扩展
extends 限定通配符的上边界
super 限定通配符的下边界
①自定义泛型方法及其应用
类型推断,返回xy的交集:
private static<T> T add(T x,T y)
add(3,5);
Number x1 = add(3.5,3);
Object x2 = add(3,"abc");
引用不能是基本数据类型:
private static <T> void swap(T[] a,int i,int j){
T tmp = a[i];
a[i] = a[j];
a[j] = tmp;
}
swap(new String[]{"abc","xyz","itcast"},1,2);
//swap(new int[]{1,3,5,4,5},3,4);T的引用不能是基本数据类型(int)
②自定义泛型方法的练习与类型推断总结
实现自动将Object类型的对象转换成其他类型:
private static <T> T autoConvert(Object obj){
return (T)obj;
}
Object obj = "abc";
String x3 = autoConvert(obj);
定义一个方法,可以将任意类型的数组中的所有元素填充为相应类型的某个对象:
private static <T> void fillArray(T[] a,T obj){
for(int i=0;i<a.length;i++){
a[i] = obj;
}
}
采用自定义泛型方法的方式打印出任意参数化类型的集合中的所有内容:
public static void printCollection(Collection<?> collection){
System.out.println(collection.size());
for(Object obj : collection){
System.out.println(obj);
}
}
public static <T> void printCollection2(Collection<T> collection){
System.out.println(collection.size());
for(Object obj : collection){
System.out.println(obj);
}
}
③自定义泛型类的应用
在类身上定义泛型
public class GenericDao<E> {
public void add(E x){
}
public E findById(int id){
return null;
}
}
④通过反射获得泛型的实际类型参数
得到方法的参数的实际类型
public static void applyVector(Vector<Date> v1){
}
Method applyMethod = GenericTest.class.getMethod("applyVector", Vector.class);
Type[] types = applyMethod.getGenericParameterTypes();
ParameterizedType pType = (ParameterizedType)types[0];
System.out.println(pType.getRawType());
System.out.println(pType.getActualTypeArguments()[0]);
}
十、类加载器及其委托机制的分析
程序出现类,类加载器就要这个类class文件加载到内存中并处理得到了字节码
java虚拟机中可以安装多个加载器,系统默认三个主要加载器,每个负责特定位置的类:bootStrap,extclassloader,appclassloader。
类加载器也是java类,其也要被类加载器加载,显然必须有第一个加载器不是java类,这正是bootStrap
java虚拟机中的所有类加载器采用具有父子关系的树形结构进行组织,在实例化每个来加载器对象时,需要为其指定一个父级类加载器对象或默认采用系统类加载器为其类加载器加载。
每个类加载器加载类时,要先委托给其上级类加载器。
如果自己写类加载器,并且希望不让他委托给其上级类加载器加载,需要特殊编写
自定义类加载器的编写原理分析
首先继承抽象classloader类,编写覆盖findclass方法
调用这个加载器类是通过loadclass方法加载想要加载的类。
模板方法设计模式:
父类->loadClass/findClass/得到class文件转成字节码-
>definClass()
① 应用代码示例
编写对class文件进行加密的工具类
String srcPath = args[0];
String destDir = args[1];
FileInputStream fis = new FileInputStream(srcPath);
String destFileName = srcPath.substring(srcPath.lastIndexOf('//')+1);
String destPath = destDir + "//" + destFileName;
FileOutputStream fos = new FileOutputStream(destPath);
cypher(fis,fos);
fis.close();
fos.close();
}
private static void cypher(InputStream ips ,OutputStream ops) throws Exception{
int b = -1;
while((b=ips.read())!=-1){
ops.write(b ^ 0xff);
}
}
编写和测试自己编写的解密类加载器
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
String classFileName = classDir + "//"
+ name.substring(name.lastIndexOf('.')+1) + ".class";
try {
FileInputStream fis = new FileInputStream(classFileName);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
cypher(fis,bos);
fis.close();
System.out.println("aaa");
byte[] bytes = bos.toByteArray();
return defineClass(bytes, 0, bytes.length);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
调用:
Class clazz = new MyClassLoader("itcastlib").loadClass
("cn.itcast.day2.ClassLoaderAttachment");
Date d1 = (Date)clazz.newInstance();
System.out.println(d1);
十一、动态代理类的作用与原理及AOP概念
编写一个与目标类具有相同接口的代理类,代理类的每个方法调用目标类的相同方法,并在调用方法时加上系统功能代码。
在配置文件中配置是使用目标类还是代理类,这样以后很容易切换,譬如,想要日志功能时就配置代理类,否则配置目标类,这样增加系统功能很容易,运行一段时间后,想去掉系统功能也
很容易。
aop的目标就是使交叉业务模块化,这正好使用代理技术解决
要为系统各种接口的类增加代理功能,那将需要很多代理类,如果都是用静态代理方式很麻烦,所以应用jvm动态生成的类就很好了。
jvm在运行期间动态生成出类的字节码,这种动态生成的类往往被用做代理类,即动态代理类。
jvm生成的动态类必须实现一个或多个接口,所以jvm生成的动态类只能用作具有相同接口的目标类的代理。如果目标类没有实现接口的功能,那么怎么告诉jvm也生成跟目标类定义的方法,
jvm没办法,只能通过第三方库
CGLIB库可以动态生成一个类的子类,一个类的子类也可以用作该类的代理,所以,如果要为没有实现接口的类生成动态代理类,那么可以使用CGLIB库。
代理类的各个方法除了调用目标的相应方法和对外返回目标返回的结果外,还可以在代理方法中的四个位置加上系统功能代码:
1在调用目标方法之前
2在调用目标方法之后
3在调用目标方法前后都有
4在处理目标方法异常的catch块中
①应用实例
创建动态类及查看其方法列表信息
注意---StringBuilde与StringBuffer:StringBuilder用在单线程,StringBuffer用在多线程,因为他要考虑安全因素
Class clazzProxy1 = Proxy.getProxyClass(Collection.class.getClassLoader(), Collection.class);
System.out.println(clazzProxy1.getName());
System.out.println("----------begin constructors list----------");
Constructor[] constructors = clazzProxy1.getConstructors();
for(Constructor constructor : constructors){
String name = constructor.getName();
StringBuilder sBuilder = new StringBuilder(name);
sBuilder.append('(');
Class[] clazzParams = constructor.getParameterTypes();
for(Class clazzParam : clazzParams){
sBuilder.append(clazzParam.getName()).append(',');
}
if(clazzParams!=null && clazzParams.length != 0)
sBuilder.deleteCharAt(sBuilder.length()-1);
sBuilder.append(')');
System.out.println(sBuilder.toString());
}
创建动态类的实例对象及调用其方法
Constructor constructor = clazzProxy1.getConstructor(InvocationHandler.class);
class MyInvocationHander1 implements InvocationHandler{
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
return null;
}
}
Collection proxy1 = (Collection)constructor.newInstance(new MyInvocationHander1());
System.out.println(proxy1);
proxy1.clear();
完成InvocationHandler对象的内部功能
Object proxy3 = Proxy.newProxyInstance(
target.getClass().getClassLoader(),
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;
Proxy:动态代理类,其中主要包含以下内容:
Protected Proxy(InvocationHandler h):构造函数,估计用于给内部的h赋值。
Static Class getProxyClass (ClassLoader loader, Class[] interfaces):获得一个代理类,其中loader是类装载器,interfaces是真实类所拥有的全部接口的数组。
Static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h):返回代理类的一个实例,返回后的代理类可以当作被代理类使用。