黑马程序员——高新技术加强学习笔记与心得

来源:互联网 发布:java微信开发api文档 编辑:程序博客网 时间:2024/06/01 09:45
---------------------- ASP.Net+Android+IOS开发、.Net培训、期待与您交流! ----------------------


java ee-->Java  Enterprise Editon Java企业级应用

ide -->Integrated Development Environment 集成开发环境
jms-->Java Message Service java消息服务
jmx-->Java Management Extension java管理扩展

Perspective与view的关系(透视图是很多视图组成的集合)
overload vs override 重载与重写
享元模式 flyweight
有很多个小的对象他们有很多属性相同把他们变成一个对象,那些不同的属性把他们变成方法的参数,称之为外部状态,那些相同的属性称之为这个对象的内部状态

java编译和运行环境的设置
window-->preferences的java目录下的Compiler和Installed JREs 进行设置
工作
区间的配置: Content assist 内容助理,快捷键 解除绑定:remove binding
为了兼容:高版本的java能运行低版本javac编译的程序

MyEclipse中模版的运用window-->preferences-->java-->Editor-->Templates

JDK1.5的新特性

静态导入
import语句可以导入一个类中或者某个包中的所有类

import static语句导入一个类中的某个静态方法火所有静态方法

import static java.lang.Math.*;

可变参数
可变参数的特点:
只能出现在参数列表的最后
... 位于变量类型和变量名之间,前后有无空格都可以
调用可变参数的方法时,编译器为该可变参数隐含创建一个数组,在方法体中以数组的形式访问可变参数

public class VariableParameter {
public static void main(String[] args) {
System.out.println(add(2, 3));
System.out.println(add(2, 3, 6));
}

public static int add(int x, int... args) {
int sum = x;
for (int i = 0; i < args.length; i++) {
sum += args[i];
}
return sum;
}
}

增强for循环
语法:
for(type 变量名:集合变量名) {...}
注意事项:
迭代变量必须在( )中定义
集合变量可以是数组或实现论文iterator接口的集合类

基本数据类型的自动拆箱与装箱

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

注:用普通类模拟枚举说明枚举就是一个特殊的类,枚举中的成员就是这个类的一个实例

枚举的基本应用

枚举只有一个成员时,就可以作为一种单例的实现方式

public class EnumTest {

public static void main(String[] args) {

WeekDay1 weekDay = WeekDay1.MON;
System.out.println(weekDay.nextDay());
// System.out.println(weekDay.toString());

WeekDay weekDay2 = WeekDay.FRI;
System.out.println(weekDay2.toString());
System.out.println(weekDay2.name());
System.out.println(weekDay2.ordinal());
System.out.println(WeekDay.valueOf("SUN"));
System.out.println(WeekDay.values().length);

}

// 带有构造函数的枚举
public enum WeekDay {
SUN(1), MON(), TUE, WED, THE, FRI, SAI;
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类名就是Class
补充:java类用于描述一类事物的共性,该类事物有什么属性,没有什么属性
Class类代表java类,它的各个实例对象对应各个类在内存中的字节码
如何得到各个字节码对应的实例对象(Class类型)
类名.class
对象.getClass()
Class.forName("类名")
九个预定义Class实例对象
参看Class.isPrimitive方法的帮助
int.class == Integer.TYPE true
int.class.isPrimitive true
String.class.isPrimitive false
有九种预定义的 Class 对象,表示八个基本类型和 void。这些类对象由 Java 虚拟机创建,与其表示的基本类型同名,即 boolean、byte、char、short、int、long、float 和 double
数组类型的Class实例对象
Class.isArray()
总之,只要是在源程序中出现的类型,都有各自的Class实例对象,例如,int[],void

反射
反射就是把java类中的各种成分映射成相应的java类
表示java类的Class类提供了一系列的方法,来获得其中的变量,方法,构造函数,修饰符,包等信息,这些信息是通过相应类的实例对象来表示,它们是Field、Method、Contructor、Package等等
一个类中的每个成员都可以用相应的反射API类的一个实例对象来表示

Constructor类
Constructor类代表某个类中的一个构造方法

class-->constructor-->new object
//得到一个构造方法,获得方法时要用到类型
Constructor constructor1 = String.class.getConstructor
(StringBuffer.class);
//创建实例对象,调用获得的方法时要用到上面相同类型的实例对象
String str2 = (String) constructor1.newInstance(new StringBuffer("abc")); //通过反射方式

Class.newInstance()方法
例子:String obj = (String) Class.forName("java.lang.String").newInstance();
该方法内部先得到默认的构造方法,然后用该构造方法创建实例对象
给方法内部的具体代码用到了缓存机制来保存默认构造方法的实例对象

Field类
Field类代表某个类中的一个成员变量

Method类
Method类代表某个类中的一个成员方法

用反射的方法执行某个类中的main方法
目标:
写一个程序,这个程序能够根据用户提供的类名,去执行该类中的main方法。用普通方式调完后,要明白为什么要用反射的方式去调?

数组的反射
具有相同维数和元素类型的数组属于同一个类型,即具有相同的Class实例对象
代表数组的Class实例对象的getSuperclass()方法返回的父类为Object类对应的Class
基本数据类型的一维数组可以被当作Object类型使用,不能当作Object[]类型使用;非基本类型的一维数组,既可以当作Object类型使用,又可以当作Object[]类型使用
Arrays.asList()方法在处理int[]和String[]时的差异

注:Object[] 与String[]没有父子关系,Object与String有父子关系,所以new Object[]{“aaa”,”bb”}不能强制转换成new String[]{“aaa”,”bb”};,Object x = “abc”能强制转换成String x = “abc”。
main.invoke(null, (Object)(new Object[]{“aaa”,“xxx”}));不能调用public static void main(String [] args)

补充HashCode():

黑马程序员_java高新技术


只有类的实例对象要被采用哈希算法进行存储和检索时,这个类才需要按要求覆盖hashCode方法。即使程序暂时不会用到当前类的hashCode方法,但是为它提供一个hashCode方法也不会有什么不好,没准以后什么时候又用到这个方法了。所以,通常要求hashCode方法和equals方法一并被同时覆盖。
提示:
(1)通常来说,一个类的两个实例对象用equals方法比较的结果相等时,它们的哈希码也必须相等,但反之则不成立,即equals方法比较结果不想等的对象可以有相同的哈希码,或者说哈希码相同的两个对象的equals方法比较的结果可以不等。
(2)当一个对象被存储进HashSet集合中以后,就不能修改这个对象中的那些参与计算哈希值的字段了,否则,对象修改后的哈希值与最初存储进HashSet集合中时的哈希值就不同了,在这种情况下,即使在contains方法使用该对象的当前引用作为的参数去HashSet集合中检索对象,也将返回找不到对象的结果,这也会导致无法从HashSet集合中单独删除当前对象,从而造成内存泄漏。

反射的作用->实现框架功能
框架与工具类有区别,工具类被用户的类调用,而框架则是调用用户提供的类
如:你做的门调用锁,锁是工具,你做的门被房子调用,房子是框架,房子和锁都是别人要提供的。
框架要解决的核心问题
因为在写程序时无法知道要被调用的类名,所以,在程序中无法直接new某个类的实例对象,而要用反射方式来做

package cn.itcast.day1;

public class ReflectPoint {
private int x;
public int y;
public String str1 = "ball";
public String str2 = "basketball";
public String str3 = "itcast";

public ReflectPoint(int x, int y) {
this.x = x;
this.y = y;
}

@Override
public String toString() {
return str1 + ":" + str2 + ":" + str3;
}

@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + x;
result = prime * result + y;
return result;
}

@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
final ReflectPoint other = (ReflectPoint) obj;
if (x != other.x)
return false;
if (y != other.y)
return false;
return true;
}

}

package cn.itcast.day1;

import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Arrays;

public class ReflectTest {


public static void main(String[] args) throws Exception {
// TODO Auto-generated method stub

String str1 = "abc";
Class cls1 = str1.getClass();
Class cls2 = String.class;
Class cls3 = Class.forName("java.lang.String");

System.out.println(cls1 == cls2);
System.out.println(cls1 == cls3);

System.out.println(cls1.isPrimitive());
System.out.println(int.class.isPrimitive());
System.out.println(int.class == Integer.class);
System.out.println(int.class == Integer.TYPE);
System.out.println(int[].class.isPrimitive());
System.out.println(int[].class.isArray());

// new String(new StringBuffer("abc"))
Constructor constructor1 = String.class
.getConstructor(StringBuffer.class);
String str2 = (String) constructor1
.newInstance(new StringBuffer("abc"));
System.out.println(str2.charAt(2));

String obj = (String) Class.forName("java.lang.String").newInstance();

ReflectPoint pt1 = new ReflectPoint(3, 5);
Field fieldY = pt1.getClass().getField("y");
// fieldY的值是多少? 是5,错!fieldY不是对象上的变量,而是类上的,而是类上,要用它去取某个对象上的值
System.out.println(fieldY);
System.out.println(fieldY.get(pt1));

Field fieldX = pt1.getClass().getDeclaredField("x");
fieldX.setAccessible(true); // 暴力反射
System.out.println(fieldX.get(pt1));

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

// str1.charAt(1);
Method methodcharAt = String.class.getMethod("charAt", int.class);
// 如果传递给Method对象的invoke()方法的第一个参数为null,说明该Method对象对应的是一个静态方法
System.out.println(methodcharAt.invoke(str1, 1));
System.out.println(methodcharAt.invoke(str1, new Object[] { 2 })); // 自动装箱成为Integer

// TestArguments.main(new String[] { "111", "222", "333" });
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" });

// 所有具有相同元素类型和维数的数组都共享该 Class 对象
int[] a1 = new int[] { 1, 2, 3 };
int[] a2 = new int[4];
int[][] a3 = new int[2][3];
String[] a4 = new String[] { "a", "b", "c" };
System.out.println(a1.getClass() == a2.getClass()); // true
System.out.println(a1.getClass() == a4.getClass()); // false
System.out.println(a1.getClass() == a3.getClass()); // false
System.out.println(a1.getClass().getName()); // [I
System.out.println(a1.getClass().getSuperclass().getName()); // java.lang.Object
System.out.println(a4.getClass().getSuperclass().getName());
System.out.println(a3.getClass().getSuperclass().getName());

String a = "";
System.out.println(a.getClass().getSuperclass().getName()); // java.lang.Object

// 基本数据类型不是Object
Object aObj1 = a1;
Object aObj2 = a4;
// Object[] aObj3 = a1;
Object[] aObj4 = a3;
Object[] aObj5 = a4;

System.out.println(a1);
System.out.println(a4);
System.out.println(Arrays.asList(a1));
System.out.println(Arrays.asList(a4));

printObject(a4);

printObject("xyz");

}

private static void printObject(Object obj) {
Class clazz = obj.getClass();
if (clazz.isArray()) {
int len = Array.getLength(obj);
for (int i = 0; i < len; i++) {
System.out.println(Array.get(obj, i));
}
} else {
System.out.println(obj);
}

}

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);

}
}

}
}

class TestArguments {
public static void main(String[] args) {
for (String arg : args) {
System.out.println(arg);
}

}

}

package cn.itcast.day1;

import java.io.FileInputStream;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Properties;

public class ReflectTest2 {


public static void main(String[] args) throws Exception {
// TODO Auto-generated method stub
// 一定要记住用完整的路径,但完整的路径不是硬编码,而是运算出来的
// InputStream ips = new FileInputStream("conifg.properties");

// InputStream ips = ReflectTest2.class.getClassLoader()
// .getResourceAsStream("cn/itcast/day1/conifg.properties");
// InputStream ips = ReflectTest2.class
// .getResourceAsStream("resource/conifg.properties");
InputStream ips = ReflectTest2.class
.getResourceAsStream("/cn/itcast/day1/resource/conifg.properties");
Properties prop = new Properties();
prop.load(ips);
ips.close(); // 这里先将关联的物理资源释放,本对象由JVM管理
String className = prop.getProperty("className");
Collection collections = (Collection) Class.forName(className)
.newInstance();

// Collection collections = new HashSet();
ReflectPoint pt1 = new ReflectPoint(3, 3);
ReflectPoint pt2 = new ReflectPoint(5, 5);
ReflectPoint pt3 = new ReflectPoint(3, 3);
collections.add(pt1);
collections.add(pt2);
collections.add(pt3);
collections.add(pt1);

// pt1.y = 7;
// collections.remove(pt1);

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

}

}

怎样导入一个已有的工程
首先将源文件复制到当前工作空间,然后选择导入已有工程: File-->Import-->General-->Existing Projects into Workspace

内省->了解JaveBean
IntroSpector-->JavaBean-->特殊的Java类
JavaBean是一种特殊的java类,主要用于传递数据信息,这种java类中的方法主要用于访问私有的字段,且方法名符合某种命名规则
如果要在两个模块之间传递多个信息,可以将这些信息封装到一个JavaBean中,这种JavaBean的实例对象通常称之为值对象(Value Object,简称VO)
一个符合JavaBean特点的类可以当作普通类一样进行使用,但把它当JavaBean用会带来一些额外的好处
Java EE开发中,经常要使用到JavaBean。很多环境就要求按JavaBean方式进行操作
JDK中提供了对JavaBean进行操作的一些API就称为内省

class Person {
private int x;

public int getAge() {
return x;
}

public void setAge(int age) {
this.x = age;
}
}

特点:
Age-->如果第二个字母是小的,则把第一个字母变成小的-->age

gettime-->time
setTime-->time
getCPU-->CPU

内省综合案例
PropertyDescriptor类
PropertyDescriptor 描述 Java Bean 通过一对存储器方法导出的一个属性
采用遍历BeanInfo的所有属性方式来查找和设置某个ReflectPont对象的x属性。在程序中把一个类当作JavaBean来看,就是调用IntroSpector.getBeanInfo方法,得到的BeanInfo对象封装了把这个类当作JavaBean看的结果信息

import java.beans.*;
import java.lang.reflect.*;

public class IntroSpectorTest {

public static void main(String[] args) throws Exception {
ReflectPoint pt1 = new ReflectPoint(3, 5);

String propertyName = "x";
// "x"-->"X"-->"getX"==>MethodGetX-->
Object retVal = getProperty(pt1, propertyName);
System.out.println(retVal);

Object value = 7;

setProperty(pt1, propertyName, value);

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

}

private static void setProperty(Object pt1, String propertyName,
Object value) throws IntrospectionException,
IllegalAccessException, InvocationTargetException {
PropertyDescriptor pd2 = new PropertyDescriptor(propertyName, pt1
.getClass());
Method methodSetX = pd2.getWriteMethod();
methodSetX.invoke(pt1, value);
}

private static Object getProperty(Object pt1, String propertyName)
throws IntrospectionException, IllegalAccessException,
InvocationTargetException {
// PropertyDescriptor pd = new PropertyDescriptor(propertyName, pt1
// .getClass());
// Method methodGetX = pd.getReadMethod();
// Object retVal = methodGetX.invoke(pt1);

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;
}

}

Beanutils工具包

黑马程序员_java高新技术

了解注解及java提供的几个基本注解(JDK1.5新特性)
@SuppereddWarnings
@Deprecated
@Override
总结:
注解相当于一种标记,在程序中加了注解就等于为程序打上了某种标记,没加,则等于没有某种标记,以后,javac编译器,开发工具和其他程序可以用反射来了解你的类及各种元素上有无何种标记,看你有什么标记没就去干相应的事。标记可以加在包,类,字段,方法,方法的参数以及局部变量上。

注解的应用结构图

注解就相当于一个你的源程序中要调用的一个类,要在源程序中应用某个注解,得先准备好了这个注解类。就像你要调用某个类,得先有开发好这个类

自定义注解及其应用
@Retention元注解有三种取值:
RetentionPliicy.SOURCE、RetentionPolicy.CLASS、RetentionPolict.TUNTIME;分别对应:java源文件-->class文件-->内存中的字节码
@SuppereddWarnings 属性值:SOURCE
@Override 属性值:SOURCE
@Deprecated 属性值:RUNTIME
@Target元注解
Target默认值为任何元素

为注解增加基本属性
定义基本类型的属性和应用属性
在注解类中增加String color();
为属性指定缺省值
String color() default "yellow";
value属性:
String valule() default "zxx";
如果注解中有一个名称为value的属性,且你只想设置value属性(即其他属性都采用默认值或者你只有一个value属性),那么可以省略value=部分,例如:@MyAnnotation("lhm)
为注解增加高级属性
数组类型的属性(如果数组属性中只有一个元素,这时候属性值部分可以省略大括号)
枚举类型的属性
注解类型的属性

package cn.itcast.day2;

import java.lang.annotation.*;

import cn.itcast.day1.EnumTest;

//元注解
//元数据
//元信息
//说明只有一个value属性,并且其值是枚举
@Retention(RetentionPolicy.RUNTIME)
@Target( { ElementType.METHOD, ElementType.TYPE })
public @interface ItcastAnnotation {
String color() default "blue";

String value();

int[] arrayAttr() default { 3, 4, 5 };

EnumTest.TrafficLamp lamp() default EnumTest.TrafficLamp.RED;

MetaAnnotation annotationAttr() default @MetaAnnotation("lhm");

Class clazz() default AnnotationTest.class;
}

package cn.itcast.day2;

public @interface MetaAnnotation {
String value();

}

package cn.itcast.day2;

import java.lang.annotation.Annotation;

@ItcastAnnotation(clazz = AnnotationTest.class, annotationAttr = @MetaAnnotation("flx"), color = "red", value = "abc", arrayAttr = {
1, 2, 3 })
public class AnnotationTest {

@SuppressWarnings("deprecation")
// 只有一个属性时可以简写
@ItcastAnnotation("xyz")
public static void main(String[] args) {
// TODO Auto-generated method stub
System.runFinalizersOnExit(true);

if (AnnotationTest.class.isAnnotationPresent(ItcastAnnotation.class)) {
ItcastAnnotation annotation = 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());
}

}

@Deprecated
public static void sayHello() {
System.out.println("hi,传智播客");
}

}

体验泛型(JDK1.5新特性)
使用泛型集合,可以将一个集合中的元素限定为一个特定类型,集合中只能存储同一个类型的对象,这样更安全,并且当从集合中获取一个对象时,编译器也可以知道这个对象的类型,不需要对对象进行强制类型转换,这样更方便。
泛型是提供给javac编译器使用的,可以限定集合中的输入类型,让编译器挡住源程序中的非法输入,编译器编译带类型说明的集合时会去除掉"类型"信息,使程序运行效率不受影响,对于参数化的泛型类型,getClass()方法的返回值和原始类型完全一样,由于编译生成的字节码会去掉泛型的类型信息,只要能跳过编译器,就可其他类型到集合,再调用其add方法即可

跳过编译器:
ArrayList<String> collection = new ArrayList<String>();
ArrayList<String> collection3 = new ArrayList<Integer>();
System.out.println(collection3.getClass() == collection.getClass()); //true
collection3.getClass().getMethod("add", Object.class).invoke(collection3, "abc");
System.out.println(collection3.get(0));

了解泛型
参数化类型与原始类型的兼容性:
Collection<String> c = new Vector(); //产生警告
Collection c = new Vector<String>(); //产生警告
参数化类型不考虑类型参数的继承关系:
Vector<String> v = new Vector<Object>(); //错误
Vector<Object> v = new Vetcot<String>(); //也错误
在创建数组实例时,数组的元素不能使用参数化的类型
Vector<Integer>[] vectorList = new Vector<Integer>[10]; //错误

泛型中的?通配符
问题:
定义一个方法,该方法用于打印出任意参数化类型的集合中的所有数据,该方法如何定义呢?
错误方式:
public static void printCollection(Colle

ction<Object> cols) {
for(Object obj:cols) {
System.out.println(obj);
}

}
正确方式:
public static void printCollection(Collection<?> cols) {
for(Object obj:cols) {
System.out.println(obj);
}
//cols.add("string");//错误,因为它不知自己未来匹配就一定是String
cols.size();//没错,此方法与类型参数没有关系
cols = new HashSet<Date>();
}
总结:
使用?通配符可以引用其他各种参数化的类型,?通配符定义的变量主要用作引用,可以调用与参数化无关的方法,不能调用与参数化有关的方法

泛型中的?通配符的扩展
限定通配符的上边界:
正确:Vector<? extends Number> x = new Vector<Integer>();
错误: Vector<? extends Number> x = new Vector<String>();
限定通配符的下边界:
正确:Vector<? super Integer> x = new Vector<Number>();
错误: Vector<? super Integer> x = new Vector<Byte>();
提示:
限定通配符总是包括自己

泛型集合类的综合案例

HashMap<String, Integer> maps = new HashMap<String, Integer>();
maps.put("zxx", 20);
maps.put("lhm", 35);
maps.put("flx", 33);

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

自定义泛型
说明:java中的泛型类似于C++的模版,但是这种相似性仅限于表面,java语言的泛型基本上完全是在编译器中实现的,用于编译器执行类型检查和类型推断,然后生成普通的非泛型的字节码。这种实现技术称为擦除(编译器使用泛型类型信息保证类型安全,然后在生成字节码之前将其清除)
交换数组中的两个元素的位置的泛型方法语法定义如下:
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,5); //错误 因为编译器不会对new int[] 中的int自定拆箱和装箱了,因为new int[] 本身已经是对象了
除了在应用泛型时可以使用extends限定符,在定义泛型时也可以使用extends限定符,并且可以用&指定多个边界,如
<V extends Serializable&cloneable>void method() {}
普通方法、构造方法和静态方法黄总都可以使用泛型
也可以用类型变量表示异常,称为参数化的异常,可以用于方法的throws列表中,但是不能用于catch字句中
private static <T extends Exception> void sayHello() throws T {
try {

} catch (Exception e) {
throw (T)e;
}
}

类型参数的类型推断
编译器判断泛型方法的世纪类型参数的过程称为类型推断,类型推断是相对于知觉推断的
根据调用泛型方法时实际传递的参数类型或返回值的类型来推断,具体规则如下:
当某个类型变量只在整个参数列表中的所有参数和返回值中的一处被应用了,那么根据调用方法时该处的实际应用类型来确定,这很容易凭着感觉推断出来,即直接根据调用方法时传递的参数类型或返回值来决定泛型参数的类型,例如:
swap(new String[3],3,4) -> static <E> void swap(E[] a, int i, int j)
当某个类型变量在整个参数列表中的所有参数和返回值中的多处被应用了,如果调用方法时这多处的实际应用类型都对应同一种类型来确定,这很容易凭着感觉推断出来,例如:
add(3,5) -> static <T> T add(T a, T b)
当某个类型变量在整个参数列表中的所有参数和返回值中的多处被应用了,如果调用方法时这多处的实际应用类型对应到了不同的类型,且没有使用返回值,这时候取多个参数中的最大交集类型,例如,下面语句实际对应的类型就是Number了,编译没问题,只是运行时出问题:
fill(new Integer[3],3.5f) -> static <T> void fill(T[] a, T v)
当某个类型变量在整个参数列表中的所有参数和返回值中的多处被应用了,如果调用方法时这多处的实际应用类型对应到了不同的类型,并且使用返回值,这时候优先考虑返回值的类型,例如,下面语句实际对应的类型就是Integer了,编译将报告错误,将变量x的类型改为float,对比eclipse报告的错误提示,接着再将变量x类型改为Number,则没有了错误:
int x =(3,3.5f) -> static <T> T add(T a, T b)
参数类型的类型推断具有传递性,下面第一种情况推断实际参数类型为Object,编译没有问题,而第二种情况则根据参数化的Vector类实例将类型变量直接确定为String类型,编译将出现问题:
copy(new Integer[5],new String[5]) -> static <T> void copy(T[] a,T[] b)
copy(new Vector<String>(),new Integer[5]) -> static <T> void copy(Collector<T> a,T[] b)

定义泛型类型
如果类的实例对象中的多处都要用到同一个泛型参数,即这些地方引用搞的泛型类型要保持同一个实际类型时,这时候就要采用泛型类型的方式进行定义,也就是类级别的泛型,语法格式如下:
publi class GenericDao<T> {
  private T field1;
  public void save(T obj) {}
  public T getById(int id) {}
}
类级别的泛型是根据引用该类名时指定的类型信息来参数化类型变量的,如下两种方式都可以
GenericDao<String> dao = null;
new GenericDao<String>();
注意:
在对泛型类型进行参数化时,类型参数的实例必须是引用类型,不能是基本类型
当一个变量被声明为泛型时,只能被实例变量、方法和内部类调用,而不能被静态变量和静态方法调用。因为静态成员是被所有参数化的类所共享的所以静态成员不应该有类级别的类型参数

通过反射获得泛型的参数化类型
Class GenericalReflection {
public static void main(String[] args) {
Method applyMethod = GenericTest.class.getMethod("applyVector",Vector.class);
Type[] types = applyMethod.getGenericParameterTypes();
ParameterizedType pType = (ParameterizedType) types[0];
System.out.println(pType.getRawType()); // class java.util.Vector
System.out.println(pType.getActualTypeArguments()[0]); // class java.util.Date
}

public static void applyVector(Vector<Date> v1) {

}
}

类加载器
java虚拟机可以安装多个类加载器系统默认三个主要的类加载器,每个类负责加载特定位置的类
BootStrap、ExtClassLoader、AppClassLoader
类加载器也是java类,因为其他是Java类的类加载器本身也要被类加载器加载,显然必须有第一个类加载器不是java类,这正是BootStrap


类加载器的委托机制

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

编写自己的类加载器
知识:
自定义的类加载器必须继承ClassLoader
loadClass方法与findClass方法
defineClass方法

AOP
交叉业务的编程问题即为面向方面的编程(Aspect oriented program,简称AOP),AOP的目标就是要是交叉业务模块化
OOP 面向对象的编程

动态代理技术
JVM可以在运行期动态生成出类的字节码,这种动态生成的类往往被用作代理类,即动态代理技术
JVM生成的动态累必须实现一个或多个接口,所以,JVM生成的动态类只能用作具有相同接口的目标类的代理
CGLIB库可以动态生成一个类的子类,一个类的子类也可以用作该类的代理,所以,如果要为一个没有实现接口的类生成动态代理类,那么可以使用CGLIB库
代理类的各个方法中通常除了要调用目标的相应方法和对外返回目标返回的结果外,还可以在代理方法中的如下四个位置加上系统功能代码:
1.在调用目标方法之前
2.在调用目标方法之后
3.在调用目标方法前后
4.在处理目标方法异常的catch块中

分析JVM动态生成的类
总结思考:
生成的类中有哪些方法,通过让其实现哪些接口的方式进行告知:
产生的类字节码必须有一个关联的类加载器对象
生成的类中的方法的代码是怎样的,也是由我们提供的。把我们的代码卸载一个约定好了接口对象的方法中,把对象传给它,它调用我的方法,相当于插入了我的代码,提供执行代码的对象就是那个InvocationHandler对象的invoke方法中加一点代码,就可以看到这些被调用运行了。

分析为什么动态类的实例对getClass()方法返回了正确结果呢?
调用代理对象的从Object类继承的hashCode、equal、或toString这几个方法时,代理对象将调用请求转发给InvocationHandler对象,对于其他方法,则不转发调用请求

//比较直观的代理示例
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.Collection;

public class ProxyTest {

public static void main(String[] args) throws Exception {
// TODO Auto-generated method stub
Class clazzProxy1 = Proxy.getProxyClass(Collection.class
.getClassLoader(), Collection.class);
System.out.println(clazzProxy1.getName());

System.out.println("----------begin constructors list");
// $Proxy0
// $Proxy0(InvocationHandler,int)
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());
}

System.out.println("----------begin methods list");
// $Proxy0
// $Proxy0(InvocationHandler,int)
Method[] methods = clazzProxy1.getMethods();
for (Method method : methods) {
String name = method.getName();
StringBuilder sBuilder = new StringBuilder(name);
sBuilder.append('(');
Class[] clazzParams = method.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());
}

System.out.println("----------begin create instance");
// Object obj = clazzProxy1.newInstance();
Constructor constructor = clazzProxy1
.getConstructor(InvocationHandler.class);
// 匿名内部类
Collection proxy1 = (Collection) constructor
.newInstance(new InvocationHandler() {
public Object invoke(Object arg0, Method arg1, Object[] arg2)
throws Throwable {
// TODO Auto-generated method stub
return null;
}
});

// System.out.println(proxy1.toString());
proxy1.clear();
// proxy1.size();

// 这里不能要可变参数,因为不是位于最后
Collection proxy2 = (Collection) Proxy.newProxyInstance(
Collection.class.getClassLoader(),
new Class[] { Collection.class }, new InvocationHandler() {
ArrayList target = new ArrayList();

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() + "runing time of"
+ (endTime = beginTime));
return retVal;
}
});
Object obj = proxy2.add("zxx");
proxy2.add("lhm");
proxy2.add("bxd");
System.out.println(proxy2.size());
System.out.println(proxy2.getClass().getName());

}
}

//类似于框架的代理实现
import java.lang.reflect.Method;

public interface Advice {
void beforeMethod(Method method);

void afterMethod(Method method);

import java.lang.reflect.Method;

public class MyAdvice implements Advice {
long beginTime = 0;

public void afterMethod(Method method) {
System.out.println("从传智播客毕业上班啦!");
long endTime = System.currentTimeMillis();
System.out.println(method.getName() + "runing time of "
+ (endTime = beginTime));

}

public void beforeMethod(Method method) {
System.out.println("到传智播客来学习啦!");
beginTime = System.currentTimeMillis();
}

}

import java.lang.reflect.*;
import java.util.*;

public class ProxyTest {

public static void main(String[] args) throws Exception {
// TODO Auto-generated method stub
Class clazzProxy1 = Proxy.getProxyClass(Collection.class
.getClassLoader(), Collection.class);
System.out.println(clazzProxy1.getName());

System.out.println("----------begin constructors list");
// $Proxy0
// $Proxy0(InvocationHandler,int)
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());
}

System.out.println("----------begin methods list");
// $Proxy0
// $Proxy0(InvocationHandler,int)
Method[] methods = clazzProxy1.getMethods();
for (Method method : methods) {
String name = method.getName();
StringBuilder sBuilder = new StringBuilder(name);
sBuilder.append('(');
Class[] clazzParams = method.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());
}

System.out.println("----------begin create instance");
// Object obj = clazzProxy1.newInstance();
Constructor constructor = clazzProxy1
.getConstructor(InvocationHandler.class);
// 匿名内部类
Collection proxy1 = (Collection) constructor
.newInstance(new InvocationHandler() {
public Object invoke(Object arg0, Method arg1, Object[] arg2)
throws Throwable {
// TODO Auto-generated method stub
return null;
}
});

// System.out.println(proxy1.toString());
proxy1.clear();
// proxy1.size();

// 这里不能要可变参数,因为不是位于最后
final ArrayList target = new ArrayList(); // 这里使用final为了供内部类访问
Collection proxy2 = (Collection) getProxy(target, new MyAdvice());
Object obj = proxy2.add("zxx");
proxy2.add("lhm");
proxy2.add("bxd");
System.out.println(proxy2.size());
System.out.println(proxy2.getClass().getName());

}

private static Object getProxy(final Object target, final Advice advice) {
Object proxy2 = Proxy.newProxyInstance(target.getClass()
.getClassLoader(),
// new Class[] { Collection.class },
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() + "runing time
// of"
// + (endTime = beginTime));
// return retVal;

advice.beforeMethod(method);
Object retVal = method.invoke(target, args);
advice.afterMethod(method);
return retVal;
}
});
return proxy2;
}
}

实现AOP功能的封装与配置

黑马程序员_java高新技术

import java.io.*;
import java.util.*;

import cn.itcast.day3.Advice;

public class BeanFactory {
Properties props = new Properties();

public BeanFactory(InputStream is) {
try {
props.load(is);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}

public Object getBean(String name) {
String className = props.getProperty(name);
Object bean = null;
try {
Class clazz = Class.forName(className);
bean = clazz.newInstance(); // 说明创建JavaBean,必须有一个不带参数的构造方法
} catch (Exception e) {
// TODO: handle exception
}
if (bean instanceof ProxyFactoryBean) {
Object proxy = null;
ProxyFactoryBean proxyFactoryBean = (ProxyFactoryBean) bean;
try {
Advice advice = (Advice) Class.forName(
props.getProperty(name + ".advice")).newInstance();
Object target = Class.forName(
props.getProperty(name + ".target")).newInstance();
proxyFactoryBean.setAdvice(advice);
proxyFactoryBean.setTarget(target);
proxy = proxyFactoryBean.getProxy();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return proxy;
}
return bean;
}

}

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

import cn.itcast.day3.Advice;

public class ProxyFactoryBean {
private Advice advice;
private Object target;

public Object getProxy() {
Object proxy2 = Proxy.newProxyInstance(target.getClass()
.getClassLoader(),
// new Class[] { Collection.class },
target.getClass().getInterfaces(), new InvocationHandler() {

public Object invoke(Object proxy, Method method,
Object[] args) throws Throwable {
advice.beforeMethod(method);
Object retVal = method.invoke(target, args);
advice.afterMethod(method);
return retVal;
}
});
return proxy2;
}

public Advice getAdvice() {
return advice;
}

public void setAdvice(Advice advice) {
this.advice = advice;
}

public Object getTarget() {
return target;
}

public void setTarget(Object target) {
this.target = target;
}

}

import java.io.InputStream;
import java.util.Collection;

public class AopFrameWorkTest {

public static void main(String[] args) throws Exception {
InputStream is = AopFrameWorkTest.class
.getResourceAsStream("config.properties");
Object bean = new BeanFactory(is).getBean("xxx");
System.out.println(bean.getClass().getName());
((Collection) bean).clear();

}

}

//config.properties 通过配置文件实现切换
#xxx=java.util.ArrayList
xxx=cn.itcast.day3.aopframework.ProxyFactoryBean
xxx.advice=cn.itcast.day3.MyAdvice
xxx.target=java.util.ArrayList

 

 

心得:

正如老师所说:学完技术加强课程之后,明显感觉到基础部分的知识掌握的更为牢固。以后应该多看视频,总结学习经验,争取为以后的技术道路扫除障碍。

---------------------- <a href="http://edu.csdn.net"target="blank">ASP.Net+Android+IOS开发</a>、<a href="http://edu.csdn.net"target="blank">.Net培训</a>、期待与您交流! ----------------------

---------------------- ASP.Net+Android+IOS开发、.Net培训、期待与您交流! ----------------------
0 0
原创粉丝点击