==
1.eclipse和myeclipse:myeclipse是eclipse的一个插件,扩展了eclipse的功能。java.exe
2.ide--->itegrity development environment
3.相对独立的项目就是一个工程,
4.设置javac与javac, window--p--java---compiler编译 ,installed jre运行时
设置快捷键:window--general---keys--content ass ist(内容助理)
5.第三方工具就是架包
6.透视图由若干个小窗口组成的,小窗口也叫视图
debug--选中变量点右键---watch
7.工程与工作台是继承的关系,一个工程可以使用工作台的设置,也可以单独进行设置
8.配置模板window--java---editor---new---ok
9.import语句可以导入一个类或者是某个包中所有的类
静态导入:导入的是一个方法也可以是一个类下所有的方法:、
如:import static java.lang.Math.max;
import static java.lang.Math.*;
10增强for循环
语法:for(type 变量名:集合变量名){}
public static int staticImport(int x, int... args) {
int sum = x;
for(int a:args){
sum+=a;
}
System.out.println(sum);
return sum;
}
11.可变参数位于参数列表的最后
int ... args
例子:
//静态导入
public static int staticImport(int x, int... args) {
int sum = x;
/*for (int i = 0; i < args.length; i++) {
sum += args[i];
}*/
for(int a:args){
sum+=a;
}
System.out.println(sum);
return sum;
}
12.自动装箱与拆箱
例子:
public static void test(){
//自动装箱,也就是自动把对象装进去,-128到127比较的地址是一样的
Integer i1=134;
Integer i2=134;
//自动拆箱,自动把对象转换为基本类型,然后进行运算
System.out.println(i2+43);
System.out.println(i1==i2);
}
13.享元模式flyweight可节省空间内存
比如自动装箱与拆箱中的byte,
定义:有很多个小的对象具有很多相同属性,把他们变成一个对象,不同的属性作为方法的参数,称为外部状态,相同的属性称为内部状态
14.每一个枚举都是一个对象
枚举的作用:就是要让某个类型的变量的取值只能为若干个固定值中的一个,否则,编译器就报错.
*采用抽象方法定义nextday()将大量的if.else语句转移成了一个个独立的类
例子:
public abstract class WeekDay {
private WeekDay() {
}
public static final WeekDay MON = new WeekDay() {
@Override
public WeekDay nextDay() {
return SUN;
}
};
public static final WeekDay SUN = new WeekDay() {
@Override
public WeekDay nextDay() {
return MON;
}
};
public abstract WeekDay nextDay();
public String getWeekDay() {
return this == MON ? "MON" : "SUN";
}
}
15.
public static void main(String[] args) {
WeekDay1 weekDay = WeekDay1.MON;
// System.out.println(weekDay.nextDay());
// System.out.println(weekDay.getWeekDay());
WeekDay weekday=WeekDay.FRI;
System.out.println(weekday.name());
System.out.println(weekday);
System.out.println(weekday.toString());
System.out.println(weekday.ordinal());
System.out.println(WeekDay.valueOf("MON"));
System.out.println(WeekDay.values());
}
//枚举相当于一个类,其中sun,mon等等相当于类的对象
public enum WeekDay{
SUN,MON,TUE,WED,THI,FRI,SAT
}
16.枚举的构造函数例子:
//枚举相当于一个类,其中sun,mon等等相当于类的对象
public enum WeekDay2{
SUN,MON,TUE,WED,THI,FRI,SAT
}
public enum WeekDay{
// 如果对象后面有内容,要在对象之后加分号,只要用到枚举对象就会调用构造函数
SUN,MON,TUE,WED,THI,FRI(),SAT(7);
//枚举的构造方法,必须是private修饰的,用的是不带参的构造函数
private WeekDay(){System.out.println("first");}
private WeekDay(int day){System.out.println("second");}
}
17,子类调用的是父类的不带参的构造函数
枚举只有一个成员时,就可以作为一种单例的实现模式
18.带有抽象方法的枚举
//交通灯用枚举实现
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;
}
}
枚举对象不用再new,不带参数构造函数不用写,因为是私有的
19.Class cla=Date.class;Class代表的是字节码,对象是由字节码创建出来
Person p1=new Person();
得到一个类的字节码方法:
类名.class
对象.getclass() 如:pl.getclass();
Class.forName("类名");如:Class.forName("java.lang.String");
20.9个预定义Class实例对象,八个基本类型的,和一个void 。如:
int.class==integer.TYPE
void.class
int.class==Integer.TYPE;
数组类型的class实例对象:class.isArray();
**总之,只要是在源程序中出现的类型,都有各自的class实例对象,例如:int[],void
21.Class例子:
public static void main(String[] args) throws Exception {
String str1 = "afd";
Class cla1 = String.class;
Class cla2 = str1.getClass();
Class cla3 = Class.forName("java.lang.String");
System.out.println(cla1 == cla2);
System.out.println(cla1 == cla3);
// 分析对象是否是原始类型,原始类型一共是九个
System.out.println(cla1.isPrimitive());
System.out.println(int.class.isPrimitive());
System.out.println(int.class == Integer.class);
// 对象Integer.TYPE方法是得到Integer类的原始数据类型
System.out.println(int.class == Integer.TYPE);
System.out.println(void.class.isPrimitive());
System.out.println(int[].class.isPrimitive());
// 是否是数组
System.out.println(int[].class.isArray());
}
22.反射技术把java类中的各种成分映射成相应的java类。java类的Class类显然提供一系列方法来获取其中的变量,方法,构造方法,修饰符,包等信息,这些信息就是用应用类的实例对象来表示,,它们是Field Mothed Contructor Package等。
//得到某一个构造函数
Constructor constructor1=String.class.getConstructor(StringBuffer.class);
//利用构造函数创建实例对象
String str=(String) constructor1.newInstance(new StringBuffer("abc"));
23.Class.newInstance()方法
//成员变量的反射
ReflectPoint pt1=new ReflectPoint(3, 5);
//field不是对象身上的变量,而是类上,要用它去取对象的值
Field fieldY=pt1.getClass().getField("y");
System.out.println(fieldY);
System.out.println(fieldY.get(pt1));
//因为x是私有的,这样取就会报错,但可以去reflectPoint类中所有声明的
//Field fieldX=pt1.getClass().getField("x");
//System.out.println(fieldX.get(pt1));
Field fieldX=pt1.getClass().getDeclaredField("x");
//把私有变量设置为可操作的
fieldX.setAccessible(true);
System.out.println(fieldX.get(pt1));
24. //实现判断类的成员变量,只要是String类型,就将String类型中所有的字符b替换为字符a
private static void changeStringValue(Object obj) {
try {
Field[] fields = obj.getClass().getFields();
for (Field field : fields) {
if (field.getType() == String.class) {
String oldValue = (String) field.get(obj);
String newValue=oldValue.replace('b', 'a');
field.set(obj, newValue);
}
}
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
谁拥有数据谁就是做这个是的专家,专家模式
25.// 成员方法的反射-----获取对应的charAt方法,并且参数是一个int
Method methodCharAt = String.class.getMethod("charAt", int.class);
//调用方法,方法的第一个参数是对象的名字,第二个参数是方法的实际参数值
System.out.println(methodCharAt.invoke(str1, 1));
26.
// 通过类名来判断执行哪一个main方法,一般方法直接用类名.方法名调用
TestArguments.main(new String[]{"111","aaa","bbb"});
//用反射实现上面的功能
String startingClassName=args[0];
Method mainMethod=Class.forName(startingClassName).getMethod("main",String[].class);
//静态方法可以直接调用,不用用对象调用,所以在invoke方法中第一个参数设置为null,
//为了兼容1.4invoke方法在接受到参数是会拆箱,比如收到一个数组,它会把数组拆分成一个一个元素看待,这样数组
//就不是一个参数了,而变成对个参数,处理这个问题的方法有两种如下
mainMethod.invoke(null, (Object)new String[]{"111","aaa","bbb"});
mainMethod.invoke(null, new Object[]{new String[]{"111","aaa","bbb"}});
27.数组是具有相同类型和相同维数的一类数的集合。
// 数组与object的关系及其反射类型
int[] a1 = new int[] { 1, 2, 3 };
int[] a2 = new int[4];
int[][] a3 = new int[2][3];
String[] a4 = new String[] { "fafd", "eee", "ffff" };
// 判断其字节码是否相同
System.out.println(a1.getClass() == a2.getClass());
// System.out.println(a1.getClass() == a3.getClass());
// System.out.println(a1.getClass() == a4.getClass());
System.out.println(a1.getClass().getName());
System.out.println(a3.getClass().getName());
System.out.println(a4.getClass().getName());
// 得到父类的名字,数组的父类是java.lang.Object,不管维数
System.out.println(a1.getClass().getSuperclass().getName());
System.out.println(a3.getClass().getSuperclass().getName());
System.out.println(a4.getClass().getSuperclass().getName());
// 因为数组全是Java.lang.Object,所以a1,a2,a3,a3都可以转换为Object
// 数组a1中装的int,int的父类不是object,所以不能将a1的值赋给object,
System.out.println(String.class.getSuperclass().getName());
Object obj1 = a1;
Object obj2 = a3;
Object obj3 = a4;
// Object [] obj4=a1;
// ojb5中装的是一个int的一维数组
Object[] obj5 = a3;
// String的父类就是object
Object[] obj6 = a4;
System.out.println(a1);
// 打印出数组的值,string数组可以正常显示,用的是jdk1.4,将a4转换为list,而a1转换时,发现对不上,所以交给1.5处理
// ,1.5就将其看做一个参数,所以打印出来就是一个对象
System.out.println(Arrays.asList(a1));
System.out.println(Arrays.asList(a4));
28.// 数组反射的应用,打印数组中的元素
private static void printObject(Object obj) {
Class cla = obj.getClass();
// 判断是否为数组
if (cla.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);
}
}
**只能得到数组中具体元素的类型,而不能得到数组的数组的类型:如;
int[] a=new int[]{1,3};
不能得到a的类型,可以得到a[1]的类型
29.arrayList:存放数据时是按先后顺序一次存放,,每一个都能放进去。
hashSet:每放一个数据都先判断一下看有没有
这个对象,如果有了,就不放了,(如果要放,必须先把相同的那个删除了,才能放)
**hashCode:作用:提高从集合中查找元素的效率,这种方式将集合分成若干个存储区域,每个对象可以计算出一个哈希码,可以将哈希码分组,每组分别对应某个存储区域,根据一个对象的哈希码就可以确定该对象应该存储在哪个区域。
**只有类的实例对象要被采用哈希算法进行存储和检索时,这个类才需要按要求覆盖hashCode方法
**通常两个对象的equals()方法结果相等时,它们的哈希码也必须相同。
**当一个对象被存储进hashSet集合中以后,就不能修改这个对象中的那些参与计算哈希码的字段,否则哈希码就不同了,这样检索对象时,也就找不到对象,从而导致无法从hashSet集合中单独删除当前对象,从而造成内存泄露。
【内存泄露:某个东西不在用了,但它依然占据内存】
例子:
//arrayList和hashSet的比较
Collection con1=new ArrayList();
ReflectPoint rp1=new ReflectPoint(3, 3);
ReflectPoint rp2=new ReflectPoint(3, 4);
ReflectPoint rp3=new ReflectPoint(3, 3);
con1.add(rp1);
con1.add(rp2);
con1.add(rp3);
con1.add(rp1);
System.out.println("arrayList:"+con1.size());
Collection con2=new HashSet();
con2.add(rp1);
con2.add(rp2);
con2.add(rp3);
con2.add(rp1);
//当一个对象被存储进hashSet集合中以后,就不能修改这个对象中的那些参与计算哈希码的字段,否则哈希码就不同了,
//这样检索对象时,也就找不到对象,从而导致无法从hashSet集合中单独删除当前对象,从而造成内存泄露。
rp1.y=10;
con2.remove(rp1);
System.out.println("hashSet:"+con2.size());
30.框架与工具类的区别:工具类被用户的类调用,而框架则是调用用户提供的类。【框架就相当于房子,而门窗则相当于自己写的类,是房子调用门窗,而锁相当于工具类,是我的门在调用锁】
31.properties等效于hashMap,内存中装的是键值对,可以把自己内存中键值存到硬盘上,也可以在初始化时把自己的值加载进来
动态传递类名
InputStream is = new FileInputStream("config.properties");
Properties ps=new Properties();
ps.load(is);
is.close();
String className=ps.getProperty("className");
Collection con1=(Collection) Class.forName(className).newInstance();
32.类加载器实现对资源文件管理和配置
// 用这种方式获得资源文件,资源文件放在src外,一定要记住完整的路径,但完整的路径不是硬编码,而是运算出来的
// InputStream is = new FileInputStream("config.properties");
// 利用类加载器实现,前面要配置到具体的包下,只能读,不能修改,也就是没有输出流
// InputStream is
// =ReflectTest.class.getClassLoader().getResourceAsStream("cn/itcast/config.properties");
// 直接利用字节码文件加载
// InputStream is
// =ReflectTest.class.getResourceAsStream("config.properties");
// 放在子包下
InputStream is = ReflectTest.class
.getResourceAsStream("resources/config1.properties");
33.内省:IntroSpector
javaBean是一种特殊的java类,一种其中含有get,set方法的类
如:
class People{
private int x;
public int getAge(){
return x;
}
public void setAge(int age){
this.x=age;
}
}
对于外面只可以看见其get和set方法,只能通过方法名得知,其中有一个age属性
Age---->如果第二个字母是小的,则把第一个字母变成小的--->age
如:gettime--->time
setTime--->time
getCPU---->CPU
34.通过内省的方式得到一个对象的get和set方法。
例子:
package cn.itcast;
import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class IntroSpectorTest {
public static void main(String[] args) throws Exception {
ReflectPoint pt1 = new ReflectPoint(2, 5);
String propertyName = "x";
Object o = 54;
setProperty(pt1, propertyName, o);
System.out.println(pt1.getX());
}
// 设置set方法
private static void setProperty(Object pt1, String propertyName, Object o)
throws IntrospectionException, IllegalAccessException,
InvocationTargetException {
// 得到属性描述,PropertyDescriptor 描述 Java Bean 通过一对存储器方法导出的一个属性。
PropertyDescriptor pd1 = getProperty(pt1, propertyName);
//获得应该用于写入属性值的方法
Method methodSetX = pd1.getWriteMethod();
methodSetX.invoke(pt1, o);
}
// 设置get方法
private static PropertyDescriptor 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);
System.out.println(retVal);
return pd;
}
}
**重构一个方法的步骤:
先是选中你要重构的方法--->鼠标点右键--->refactor-->选择方法的重构
例二:
// 设置get方法
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);
System.out.println("retVal="+retVal);*/
//第二种方法得到get方法,通过introSpector得到
Object retVal=null;
BeanInfo beanInfo=Introspector.getBeanInfo(pt1.getClass());
PropertyDescriptor[] pds=beanInfo.getPropertyDescriptors();
for(PropertyDescriptor pd:pds){
if(pd.getName().equals(propertyName)){
Method methodGetX=pd.getReadMethod();
retVal=methodGetX.invoke(pt1);
System.out.println("retVal="+retVal);
break;
}
}
return retVal;
}
35.beanUtils的好处:可以很方便的取值和设值,支持级联操作,对map也可以进行操作,javabean可以和map相互转换
//利用beanUtils类来实现取值和设值的功能,但是都是以String类型来设值和取值的
BeanUtils.setProperty(pt1, "x", 123);
System.out.println(BeanUtils.getProperty(pt1, "x"));
//data中有个setTime方法,我们可以理解data类中有个time属性,beanUtils可以
//实现级联设置值,对象pt1的属性data,然后data又是一个对象,data又有一个time属性
BeanUtils.setProperty(pt1, "birthday.time", "22");
System.out.println(BeanUtils.getProperty(pt1, "birthday.time"));
//propertyUtils也可以设值和取值,与beanUtils不同是,它是按原始类型进行设值和取值的
PropertyUtils.setProperty(pt1, "x", 867);
System.out.println(PropertyUtils.getProperty(pt1, "x"));
**36.注解
--注解用于告诉java编译器一种信息,相当于一个标记,加上相当于给程序打了一个标记,看有什么标记,就采取相应的动作,标记可以加在,包,类,字段,方法的参数等上面,也可是是局部变量上面。一个注解就是一个类,
常用的有:压缩警告,继承父类--重写,过时
//压缩注解
@SuppressWarnings("deprecation")
public static void main(String[] args) {
System.runFinalizersOnExit(true);
}
//过时注解
@Deprecated
public static void sayWorld(){
System.out.println("hi world");
}
//继承父类
@Override
public String toString() {
return str1 + "," + str2 + "," + str3;
}
37.class文件不是字节码,只有当类加载器把class文件通过一定的处理并加载到内存中后才是字节码
注解的注解是元注解
38.注解的生命周期:
java源文件阶段,class阶段,runtime运行时阶段(内存中的字节码),默认是class阶段; 【就是说注解是在什么情况下起作用】三种:在编写代码的时候(source),在编译的时候存在(class),在运行的时候存在(runtime)。
三种其实是一个枚举,枚举的名字是:RetentionPolicy
@Override src
@SuppressWarnings src
@Deprecated runtime
**class的父类是type,枚举上,注解上,类上,接口上
39.注解相当于一个类,其写法:
package cn.itcast.day2;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
// 注解的注解称为元注解,上面的设置时说此注解在运行时起作用,下面的注解是指定注解可以标在什么地方,第二个参数设置为type
// 是因为注解,接口,枚举,类的父类都是type,设置为type,说明注解可以写在注解,接口,枚举,类上
@Target({ ElementType.METHOD, ElementType.TYPE })
public @interface ItcastAnnotation {
}
引用注解的类:
package cn.itcast.day2;
@ItcastAnnotation
public class AnnotationTest {
// 压缩注解
@SuppressWarnings("deprecation")
@ItcastAnnotation
public static void main(String[] args) {
System.runFinalizersOnExit(true);
if (AnnotationTest.class.isAnnotationPresent(ItcastAnnotation.class)) {
ItcastAnnotation itcastAnnotation = AnnotationTest.class
.getAnnotation(ItcastAnnotation.class);
System.out.println(itcastAnnotation);
}
System.out.println();
}
// 过时注解
@Deprecated
public static void sayWorld() {
System.out.println("hi world");
}
}
40.注解的属性:string,int,数组,class,annotation,enum.....
例子:
package cn.itcast.day2;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import cn.itcast.day1.EnumTest;
@Retention(RetentionPolicy.RUNTIME)
// 注解的注解称为元注解,上面的设置时说此注解在运行时起作用,下面的注解是指定注解可以标在什么地方,第二个参数设置为type
// 是因为注解,接口,枚举,类的父类都是type,设置为type,说明注解可以写在注解,接口,枚举,类上
@Target({ ElementType.METHOD, ElementType.TYPE })
public @interface ItcastAnnotation {
// 给注解增加属性,默认值直接给后面添加default "blue"
String color() default "blue";
// 特殊的value
String value();
// 属性是一个数组
int[] arrayAttr() default { 3, 2, 4 };
// 属性是枚举类型
EnumTest.TrafficLamp lamp() default EnumTest.TrafficLamp.RED;
// 属性是一个注解
MetaAnnotation annotationAttr() default @MetaAnnotation("kkk");
//属性是一个类
Class ss() default Student.class;
}
在另一个类中引用:
package cn.itcast.day2;
@ItcastAnnotation(color = "red", value = "aaa", arrayAttr = { 1, 3 }, annotationAttr = @MetaAnnotation("eeee"))
public class AnnotationTest {
// 压缩注解
@SuppressWarnings("deprecation")
// 因为有默认值,所以可以不设置,如果只有一个属性需要设置值,并且此属性名value,那么就可以直接设置其值
@ItcastAnnotation("liz")
public static void main(String[] args) {
System.runFinalizersOnExit(true);
if (AnnotationTest.class.isAnnotationPresent(ItcastAnnotation.class)) {
ItcastAnnotation itcastAnnotation = AnnotationTest.class
.getAnnotation(ItcastAnnotation.class);
System.out.println(itcastAnnotation);
System.out.println(itcastAnnotation.color());
System.out.println(itcastAnnotation.value());
System.out.println(itcastAnnotation.arrayAttr().length);
System.out.println(itcastAnnotation.lamp().nextLamp().name());
System.out.println(itcastAnnotation.annotationAttr().value());
}
System.out.println();
}
}
41.泛型generic:不用进行类型转换
没有使用泛型集合,只要是对象,不管是什么类型的对对象,都可以存储进同一个集合中。使用泛型集合,可以将一集合中的预算限定为一个特定类型,集合中只能存储同一个类型的对象,这样更安全,并且当从集合获取一个对象时,编译器也可以知道这个对象的类型,不需要对对象进行强制类型转换,这样更方便
。
1.5之后如果没有使用泛型,就会有一个unchect的警告
42.**要改变一个类中某些相同的字段,如:
col1.add(3);
col1.add("fefer");
col1.add(334.43);中的col1点鼠标右键选择重构--选择name
43.package cn.itcast.day2;
/**
* 泛型的应用
*/
import java.lang.reflect.Constructor;
import java.util.ArrayList;
public class GenericTest {
public static void main(String[] args) throws Exception {
ArrayList col1 = new ArrayList();
col1.add(3);
col1.add("fefer");
col1.add(334.43);
// 虽然编译器可以通过,也就是你告诉编译器可以这么转换,但实际上是转换不过去的,所以运行时会报错
// ClassCastExecption
// int i1=(Integer) col1.get(1);
ArrayList<String> col = new ArrayList<String>();
// col.add(3);
col.add("fefer");
// col.add(334.43);
// 虽然编译器可以通过,也就是你告诉编译器可以这么转换,但实际上是转换不过去的,所以运行时会报错
// ClassCastExecption
String s = col.get(0);
System.out.println(s);
//泛型用在构造函数中,可以使构造函数不进行类型转化,不用指向具体的某个类型
Constructor<String> constructor=String.class.getConstructor(StringBuffer.class);
String str=constructor.newInstance(new StringBuffer("fer"));
System.out.println(str.charAt(1));
}
}
44.编译器编译完以后,就会去掉其类型(泛型的类型),泛型是给编译器看的。可以通过反射通过泛型。
ArrayList<Integer> col2=new ArrayList<Integer>();
col2.add(4);
//泛型是给编译器看的,在运行时,会去掉泛型,也就是col1与col2是同一个字节码
System.out.println(col1.getClass() == col2.getClass());
System.out.println("=====================");
//不能给泛型中添加别的类型的数据,但可以通过反射来实现给泛型中添加别的类型的数据
System.out.println(col2.getClass().getMethod("add", Object.class)
.invoke(col2, "fdfd"));
System.out.println(col2.get(1));
//参数类型可以引用一个原始的对象,但编译器会有警告
ArrayList<String> col3=new ArrayList();
//原始类型可以应用一个参数类型,但编译器会有警告
ArrayList col4=new ArrayList<String>();
//下面代码是不对的,因为你规定的类型是String,但是实际里面装的什么都有,所以通不过,反过来也不行
//泛型中没有继承这一说
//ArrayList<String> col3=new ArrayList<Object>();
ArrayList col5=new ArrayList<Object>();
ArrayList<String> col6=col3;
45.通配符:?表示任意类型
**限定通配符的上边界(表示的是number及number的子类):
vector<? extends Number> x=new Vector<Integer>;
**限定通配符的下边界(表示的是Integer及Integer的父类):
vector<? super Integer> x=new Vector<Number>;
// 泛型的综合应用
public static void getKeyVal() {
// 定义一个存放人名及年龄的集合
HashMap<String, Integer> map = new HashMap<String, Integer>();
map.put("zs", 32);
map.put("jian", 23);
map.put("yj", 34);
// 把集合中的元素都打印出来
Set<Map.Entry<String, Integer>> entrySet = map.entrySet();
for (Map.Entry<String, Integer> entry : entrySet) {
System.out.println(entry.getKey() + ":" + entry.getValue());
}
}
46.一个map可以看做三个集合,key集合,value集合,Map.entry集合
47.
// 泛型的使用,两个类型的交集是他们的最大公约数
private static <T> T add(T x, T y) {
return x;
}
// 利用泛型实现交换,T都是对象
private static <T> void swap(T[] a, int i, int j) {
T temp = a[i];
a[i] = a[j];
a[j] = temp;
}
//自定义泛型
public static <T extends Exception> void sayHi() throws T{
try {
} catch (Exception e) {
throw (T)e;
}
}
48.自定义泛型的例子
//把object转换为T类型的数
private static <T> T autoConvertType(Object obj){
return (T)obj;
}
//给一个任意数组中填充对应类型的任意数
private static <T> void fileArray(T[] desc,T src){
for(int i=0;i<desc.length;i++){
desc[i]=src;
}
}
//通配符的方法更有效,
private static <T> void printValue(Collection<T> col){
for(Object obj:col){
System.out.println("obj="+obj);
}
}
private static <T> void copy1(T[]desc,Collection<T> src){
for(Object obj:src){
if(obj!=null){
for(int i=0;i<desc.length;i++){
desc[i]=(T) obj;
}
}
}
}
//从一个数组赋值到相应数组
private static <T> void copy2(T[]desc,T[] src){
for(int i=0;i<desc.length;i++){
for(int j=0;j<src.length;j++){
desc[i]=src[j];
}
}
}
49.数据库的操作:crud增查修删 【dao data access object】
如果类的实际对象中的多处都要用到同一个泛型参数,既这些地方引用的泛型要保持同一个实际类型时,这时就要采用泛型类来定义。
静态方法不能用在泛型类中,如果一个类中多个方法用到泛型,那么这个类最好定义为泛型类。
泛型类的例子:
package cn.itcast.day2;
import java.util.Set;
public class GenericDao<T> {
public void add(T x) {
}
public T findById(T obj) {
return null;
}
public Set<T> findByConditions() {
return null;
}
public T findByName(String name) {
return null;
}
public void updateById(int id) {
}
public void updateByT(T obj) {
}
public void deleteById(int id) {
}
public void deleteByT(T obj) {
}
}
50.得到一个类的泛型类型:可以通过把这个类当做参数的方法而间接得到,主要用的是反射
代码如下:
GenericDao<ReflectPoint> dao=new GenericDao<ReflectPoint>();
dao.add(new ReflectPoint(3, 6));
//通过反射得到参数的类型
Method method=GenericTest.class.getMethod("applyVector", Vector.class);
//得到泛型的参数类型
Type[] type=method.getGenericParameterTypes();
//得到参数化的类型
ParameterizedType pt=(ParameterizedType) type[0];
//得到原始类型
System.out.println(pt.getRawType());
//得到实际参数类型
System.out.println(pt.getActualTypeArguments()[0]);
}
public static void applyVector(Vector<Date> v1){
}
51.加载类的工具称为类加载器。
类加载器也是一个java类,它是由BootStrap加载的,system也是有BootStrap
**BootStrap的孩子ExtClassLoader,孙子是AppClassLoader
**BootStrap负责加载JRE/lib/rt.jar
ExtClassLoader负责加载JRE/lib/ext/*.jar
AppClassLoader负责加载CLASSPATH指定的所有jar或目录
52.类加载器的委托机制:
当java虚拟机要加载一个类时,
**首先当前线程的类加载器去加载线程中的第一个类。
**如果类A中引用了类B,java虚拟机将使用加载类A的加载器加载类B
**还可以直接调用ClassLoader.loadClass()方法来指定某个类加载器去加载某个类
*****注意:每个类加载器加载类时,又是先委托给其上级类加载器【也就是孙子交给儿子,儿子又交个父亲,父亲看一下能处理就处理,如果处理不了,就交个儿子,儿子在判读,能处理就处理,如果不能处理,就交个孙子,孙子能处理就处理,处理不了就抛异常】
例子:
public static void main(String[] args) {
System.out.println(ClassLoaderTest.class.getClassLoader().getClass().getName());
//打印出来为null,说明System是一个特殊的类加载器,它不是一个类
//它嵌套在java虚拟机中
System.out.println(System.class.getClassLoader());
ClassLoader loader= ClassLoaderTest.class.getClassLoader();
while(loader!=null){
System.out.println(loader.getClass().getName());
loader=loader.getParent();
}
System.out.println(loader);
}
**打war包,点工程--》点鼠标右键--》export-->jar-->选择要打war包的文件
53.有包名的类不能调用无包名的类。
54.一个简单的加密例子:
package cn.itcast.day2;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
public class MyClassLoader {
public static void main(String[] args) throws Exception {
String srcPath = args[0];
String descDir = args[1];
FileInputStream fis = new FileInputStream(srcPath);
String descFileName = srcPath.substring(srcPath.lastIndexOf('//'));
String descPath = descDir + "//" + descFileName;
FileOutputStream fos = new FileOutputStream(descPath);
cypher(fis, fos);
fis.close();
fos.close();
}
private static void cypher(InputStream is, OutputStream os) {
try {
int b = -1;
while ((b = is.read()) != -1) {
// 把0变1,把1变0
os.write(b ^ 0xff);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
55.自定义类加载器
package cn.itcast.day2;
/***
* 自己的类加载器,其中包含对文件的加密和解密
*/
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
public class MyClassLoader extends ClassLoader {
public static void main(String[] args) throws Exception {
String srcPath = args[0];
String descDir = args[1];
FileInputStream fis = new FileInputStream(srcPath);
String descFileName = srcPath.substring(srcPath.lastIndexOf('//'));
String descPath = descDir + "//" + descFileName;
FileOutputStream fos = new FileOutputStream(descPath);
cypher(fis, fos);
fis.close();
fos.close();
}
// 实现加密的功能
private static void cypher(InputStream is, OutputStream os) {
try {
int b = -1;
while ((b = is.read()) != -1) {
// 把0变1,把1变0
os.write(b ^ 0xff);
}
} catch (IOException e) {
e.printStackTrace();
}
}
private String classDir;
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
try {
System.out.println("myClassLoader");
String classFileName = classDir + "//"
+ name.substring(name.lastIndexOf('.') + 1) + ".class";
FileInputStream fis = new FileInputStream(classFileName);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
// 进行解密
cypher(fis, bos);
fis.close();
byte[] bytes = bos.toByteArray();
return defineClass(bytes, 0, bytes.length);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public MyClassLoader() {
}
public MyClassLoader(String classDir) {
this.classDir = classDir;
}
}
56.类加载器在web项目的应用
tomcat由一个java虚拟机加载
servlet的类加载器:
apache.catalina.loader.WebappClassLoader--->apache.catalina.loader.StandardClassLoader-->
sun的AppClassLoader--.>sun的extClassLoader
**如果要把servlet打war包,那么放war包的地方也要放httpServlet的架包,因为servlet中可能要用到httpServlet中的东西。
57.代理
**程序中的代理:为已存在的多个具有相同接口的目标类的各个方法增加一些系统功能(如:异常处理,日志,事务管理,计算方法的运行时间等等),这时就要用到代理类,代理类与目标类具有相同的接口,所以代理类的每个方法调用目标类的相同方法,并在调用方法时加上系统功能代码。
**目标类形式:
class x{
void sayHello(){
System.out.print("say hello");
}
}
代理类的形式:
class xProxy{
void sayHello(){
startTime();
-------//系统代码
System.out.print("say hello");
endTime();
--------- //系统代码
}
}
**代理类在工厂模式中的好处:采用工厂模式和配置文件的方式进行管理,则不需要修改客户端程序,在配置文件中配置是使用目标类,还是代理类,这样就很容易切换。
**注:client(客户端调用程序)调用Target(目标类)和调用Proxy(代理类)的效果是一样的,
实现目标类与代理类效果一样的方案:
(一)两者实现相同的接口,JVM可以在运行期动态生成类的字节码,JVM生成的动态类必须实现一个或多个接口
(二)目标类没有实现任何接口,CGLIB库可以生成一个类的子类,把此子类可以用作该类的代理类,所以如果目标类没有实现接口时,可以使用CGLIB库
**代理类方法的位置:在调用目标方法之前、在调用目标方法之后、在调用目标方法之前后、在处理目标方法异常的catch块中
58.AOP(aspect oriented program)面向方面编程
**aop的作用:使交叉业务(系统中多个模块用到的,如:安全,事务,日志等等)模块化,可以采用将切面代码移动到原始方法的周围,这与直接在方法中编写切面嗲吗的运行效果是一样
59.stringBuilder,StringBuffer
**stringBuilder,StringBuffer都是动态的向 字符串中添加字符
**stringBuilder:单线程的化stringBuilder 的效率高,不考虑线程安全,性能高;
stringBuffer:多线程中用,需要考虑安全问题
60.动态代理的例子:
package cn.itcast.day3;
/**
* 动态代理的练习
*/
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Collection;
public class ProxyTest {
public static void main(String[] args) {
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();
// System.out.println(name);
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(constructor);
}
System.out.println("------------begin methods list--------------");
Method[] methods=clazzProxy1.getMethods();
for(Method method : methods){
String methodName=method.getName();
//System.out.println(methodName);
StringBuilder sbuilder=new StringBuilder(methodName);
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(method);
}
}
}
**字节码.newInstance【调用的是不带参数的构造方法】
61.创建代理类的实例的三种方法
//创建proxy方法一,得到它的构造函数,在创建对象,其中用到了内部类
Constructor constructor = clazzProxy1
.getConstructor(InvocationHandler.class);
// InvocationHandler是一个接口,创建InvocationHandler的实例对象
class MyInvocationHander1 implements InvocationHandler {
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
return null;
}
}
/*//方法一后
**proxy的toString()方法打印的为null
**proxy的无返回值的方法运行正常
**proxy的有返回值的方法运行时报null指针异常,因为调用invoke时返回的null与要得到的返回类型不一致*/
Collection proxy1 = (Collection) constructor
.newInstance(new MyInvocationHander1());
//System.out.println(proxy1);
// proxy1.clear();
// System.out.println(proxy1.size());
// System.out.println(proxy1.toString());
// 创建实例的方法二,直接通过匿名内部类实现
Collection proxy2 = (Collection) constructor
.newInstance(new InvocationHandler() {
public Object invoke(Object arg0, Method arg1, Object[] arg2)
throws Throwable {
return null;
}
});
//System.out.println(proxy2);
// 创建方法三,每调用一次方法,都会调用invoke方法,此时他们用的是同一个数组
Collection proxy3 = (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;
}
});
proxy3.add("hjw");
proxy3.add("yw");
System.out.println(proxy3.size());
62.
**jvm创建动态类及实例对象【
首先告诉类实现的接口,类加载器是谁,最后创建时传一个参数InvocationHandler】
**可变参数必须位于参数的最后面
63.动态生成的类的内部代码:
**InvocationHandler接口中定义invoke方法接受的三个参数说明:clien程序调用objProxy.add("abc")方法时,涉及三要素:objProxy对象,add方法,"abc"参数【代理对象,代理方法,方法接受的参数】
如://生成的Collection接口中的方法的运行原理
int size(){
return handler.invoke(this,this.getClass().getMethod("size"),null)
}
方法内部会找handler的invoke方法,在invoke方法中,又交给目标执行,既
在目标身上再执行代理,也就是调用目标,。并且把参数继续传递给目标(这个参数接受到之后可以修改),并且把目标返回值(此返回值可以改变,但类型基本要一致)给handler
**动态代理的工作原理:客户端调用代理,首先把handler对象传递给代理的构造函数,然后代理的其他方法去找刚才的handler的invoke方法,在invoke中看代理调用什么,然后目标就调用什么,最后目标把值返回给代理
**hashcode,equals,toString方法才委托给handler,对于别的方法自己实现
**invocationHandler要传递两个对象(一个是目标,一个是系统功能)
**可生成代理和插入通告的通用方法:
// 把目标作为一个参数传递进来,把系统功能(用户的建议)最为接口,有具体类时传递
private static Object getProxy(final Object target, final Advice advice) {
Object proxy= Proxy.newProxyInstance(target.getClass()
.getClassLoader(), target.getClass().getInterfaces(),
new InvocationHandler() {
public Object invoke(Object proxy, Method method,
Object[] args) throws Throwable {
advice.beforMethod(method);
Object retVal = method.invoke(target, args);
advice.afterMethod(method);
return retVal;
}
});
return proxy;
}
64.Spring的配置和aop
**javaBean必须要有一个不带参数的构造函数,创建javaBean实例对象时要用到的。
**工厂类BeanFactory负责创建目标类或代理类的实例对象,并通过配置文件实现切换,其getBean方法根据参数字符串返回一个相应的实例对象,如果参数字符串在配置文件中对应的类名不是ProxyFactoryBean,则直接返回该类的实例对象,否则,返回该类实例对象的getProxy方法返回的对象。
**beanFactory的构造方法接受代表配置文件的输入流对象
格式:
#xxx=java.util.ArrayList
xxx=cn.itcast.day3.aopFramwork.ProxyFactoryBean
xxx.advice=cn.itcast.day3.MyAdvice
xxx.target=java.util.ArrayList
**ProxyFactoryBean充当封装生成动态代理的工厂,需要为工厂类提供:目标,通知
65.beanFactory
package cn.itcast.day3.aopFramwork;
/**
* beanFactory
*/
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
import cn.itcast.day3.Advice;
public class BeanFactory {
Properties props = new Properties();
public BeanFactory(InputStream ips) {
try {
props.load(ips);
} catch (IOException e) {
e.printStackTrace();
}
}
public Object getBean(String name) {
String className = props.getProperty(name);
Object bean = null;
try {
Class clazz = Class.forName(className);
bean = clazz.newInstance();
} catch (Exception e) {
e.printStackTrace();
}
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) {
e.printStackTrace();
}
return proxy;
}
return bean;
}
}
package cn.itcast.day3.aopFramwork;
/**
* ProxyFactoryBean代理类
*/
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 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;
}
public Object getProxy() {
Object proxy = Proxy.newProxyInstance(target.getClass()
.getClassLoader(), target.getClass().getInterfaces(),
new InvocationHandler() {
public Object invoke(Object proxy, Method method,
Object[] args) throws Throwable {
advice.beforMethod(method);
Object retVal = method.invoke(target, args);
advice.afterMethod(method);
return retVal;
}
});
return proxy;
}
}
66.java1.5新特性
静态导入
可变参数
枚举
注解
泛型
java1.7新特性
map map=(name:"zxx",age:18);
BeanUtils.setProperty(map,"name","1hm");