黑马程序员——JAVA基础加强(1.5新特性)(初版)

来源:互联网 发布:编程语言排行 2017 编辑:程序博客网 时间:2024/05/20 07:15
------- android培训、java培训、期待与您交流! ----------

java ee
ide --> integrity development environment
有包名的类不能调用无包名的类

JKD1.5新特性:
1.静态导入:
 JDK1.5中可以直接使用max(2,4);不过要导入包名:import static java.lang.Math.max;
 也可以import static java.lang.Math.*;其中Math.*的意思是Math类中所有静态方法。
2.传入多个参数
 public int add(int x,int ... args){return 0;}
 其中int ...args必须放在所有参数的最后一个;
 args看做一个数组用法跟数组一样:args[i];//遍历此数组的结果与前面的参数无关。
 ...前后都可以有空格。
 整段注释:Shift+Ctrl+/
3.增强for循环
 也就是传说中的foreach循环:for(int arg:args){}
 后面的参数为一个集合、也可以是一个数组
 注意:迭代器必须在()中定义;
 ☆☆集合变量可以是数组或实现了iterable接口的集合类
 文档也说了,enhanced for 完全等同于iterator迭代器,
 也就是迭代器的另一种表达形式。
    自我总结:
    for跟foreach的区别,也就是for跟iterator的区别:
    foreach的优势:迭代速度大大增强。
    缺点:只能单向(头到尾),单层迭代。
    致命缺点:不能改变原值,只能查询。
    看知识点就得从sun公司下文档,那里永远是第一手的。
    实现了iterator接口的方法:

4.自动装箱与自动拆箱(-128--127之间也就是一个byte是常住内存的是同一个,而超过这个范围的都是重新new的,
 是两个对象,虽然值相等但是内存地址不等,所以用==来判断是false)
 享元模式: flyweight
 下面的解释貌似不大对头,==解释???
 一个经常需要用到的元素我们把它设计成一个对象,
 把其他地方设计的不一样的地方作为参数传入。
5.枚举
 为什么要有枚举
 问题:要定义星期几或性别的变量,该怎么定义?假设用1-7分别表示星期一到星期日,但有人可能会写成int weekday = 0 ;
 枚举就是要让某个类型的变量取值只能为若干个固定值中的一个,否则,编译器就会报错。
 枚举类可以让编译器在编译时就可以控制源程序中填写的非法值,普通变量的方式在开发阶段无法实现这一目标。
 用普通类如何实现枚举类功能,定义一个WeekDay的类来模拟枚举功能。
1.枚举类自定义的构造器必须是私有的。
2.每个元素就是一个公有的静态成员。
3.方法(普通、静态方法)例如:要提供nextDay()方法必须是抽象的。
 枚举类中的静态方法
 values():---->将枚举类中的元素都加入一个集合中,返回一个集合,方便遍历。
 valueOf():由字符串--->自动创建为此对象。(即枚举元素)
 普通方法
 name:类似于toString的简化版本
 ordinal:排列顺序。
 总结:枚举类是一个特殊的类,其中每个元素都是该类的一个实例对象,
 例如,可以调用WeekDay().class.getName()。
4.所有方法必须位于元素之后,并且如果元素之后有方法,必须在其后加上分号。
5.枚举只有一个成员时,就可以作为一种单例的实现方式。
6.可普通也可以抽象,可无参也可以给他参数。
☆说白了枚举的每个常量都是此类的一个对象,并将之赋值给一个大写变量。
 每一个枚举都是一个对象。
学习方法:
 先用普通类模仿一下,还可以用java.awt.Color类。
 如果想要在一个类中编写各个枚举类和调用测试类,那么可以将枚举类
 定义成调用类的内部类。
枚举类注意点:
 valueOf()会将一个字符创转化成该名字的对象。
 定义的所有方法变量都得位于对象列表之后,不然会报错。
 枚举就相当于一个类,其中也可以定义构造函数、成员变量、普通方法跟抽象方法。
 枚举元素必须位于枚举体中最开始的部分,枚举元素列表后要有分号与其他成员分隔。
 枚举元素MON和MON()的效果一样,都是调用默认的构造方法。
 如果含有抽象方法,那么每个元素就是由枚举类的子类来生成实例对象的,这些子类采用类似于内部类的方式进行定义的。
6反射(JDK1.2之后的技术,并不是新技术)

1.Class:老师说:Class就是对java类总的描述。
 我认为:其实例却为一个字节码文件。

2.如何得到各个字节码对应的实例对象(Class类型)(三种方法,一般用第三种---运行的时候可以临时送进来)
    a.类名.class  例如,System.class
    b.对象.getClass(),例如,new Date().getClass()
    c.Class.forName("类名"),例如,Class.forName("java.util.Date");
 反射就是把Java类中的各个成分映射成相应的java类。
我的总结:
    如果内存中已经有了字节码文件,也就是javac了java类,可以直接:
 类名.class 
    如果内存里面有了某个类的对象,直接:
        对象。getClass(); 
    如果没有,就先用类加载器加载,再将字节码缓存起来,同时用返回那个字节码。
        Class.forName("java.lang.String")的作用:返回字节码文件. 
----->既然最后一句可以是用类加载器加载java文件,那么 类名.class会不会有同样效果呢??
以上总结待定。

3.九个预定义的Class实例对象。//为什么说是预定义的??
 int.class == Integer.Type;
 ............
 八大基本数据类型所对应的Class实例对象
 加一个void.class;
4.数组类型的Class实例对象
 Class.isArray()
 总之,只要是在源程序中出现的类型都有各自的Class实例对象,
 例如:int[],void

5.
// 一个奇怪的问题:加载了字节码,并调用了其getMethods之类的方法,
// 但是没有看到类的静态代码块被执行,只有在第一个实例对象被创建时,
// 这个静态代码才会被执行。准确的说,静态代码块不是在类加载时被调用的,
// 而是第一个实例对象被创建时才执行的。
----->老师的这个结论很狂野。什么时候自己试试。

6.反射:反射就是把Java类中的各个成分映射成相应的java类。
 反射比较消耗性能。

7.构造器反射之后所对应的类Constructor
 得到某个类所有的构造方法:
 例子:Constructor [] constructors= Class.forName("java.lang.String").getConstructors();
 得到某一个构造方法:
 例子:      Constructor constructor = Class.forName(“java.lang.String”).getConstructor(StringBuffer.class);
  //获得方法时要用到类型
 创建实例对象:
 通常方式:String str = new String(new StringBuffer("abc"));
 反射方式: String str = (String)constructor.newInstance(new StringBuffer("abc"));
  //调用获得的方法时要用到上面相同类型的实例对象
 Class.newInstance()方法:
 例子:String obj = (String)Class.forName("java.lang.String").newInstance();
 该方法内部先得到默认的构造方法,然后用该构造方法创建实例对象。
 该方法内部的具体代码是怎样写的呢?用到了缓存机制来保存默认构造方法的实例对象。
 ----->可以看下源代码。

8.Field:字段。
 Field类代表某个类中的一个成员变量
 演示用eclipse自动生成Java类的构造方法
 问题:得到的Field对象是对应到类上面的成员变量,还是对应到对象上的成员变量?
 类只有一个,而该类的实例对象有多个,如果是与对象关联,哪关联的是哪个对象呢?
 所以字段fieldX 代表的是x的定义,而不是具体的x变量。
 示例代码:
  ReflectPoint point = new ReflectPoint(1,7);
  Field y = Class.forName("cn.itcast.corejava.ReflectPoint").getField("y");
  System.out.println(y.get(point));
  //Field x = Class.forName("cn.itcast.corejava.ReflectPoint").getField("x");
  Field x = Class.forName("cn.itcast.corejava.ReflectPoint").getDeclaredField("x");
  x.setAccessible(true);
  System.out.println(x.get(point));

 一个问题,我把自己的变量定义成private,就是不想让人家访问,可是现在人家用暴力反射还是能够访问我,
 这说不通啊,能不能让人家用暴力反射也访问不了我。首先,private主要是给javac编译器看的,
 希望在写程序的时候,在源代码中不要访问我,是帮助程序员实现高内聚、低耦合的一种策略。
 你这个程序员不领情,非要去访问,那我拦不住你,由你去吧。同样的道理,
 泛型集合在编译时可以帮助我们限定元素的内容,这是人家提供的好处,
 而你非不想要这个好处,怎么办?绕过编译器,就可以往集合中存入另外类型了。

9.暴力反射

10.Method类
 Method类代表某个类中的一个成员方法
 得到类中的某一个方法:
 例子:      Method charAt = Class.forName("java.lang.String").getMethod("charAt", int.class);
 调用方法:
 通常方式:System.out.println(str.charAt(1));
 反射方式: System.out.println(charAt.invoke(str, 1));
 如果传递给Method对象的invoke()方法的第一个参数为null,这有着什么样的意义呢?说明该Method对象对应的是一个静态方法!
 jdk1.4和jdk1.5的invoke方法的区别:
 Jdk1.5:public Object invoke(Object obj,Object... args)
 Jdk1.4:public Object invoke(Object obj,Object[] args),
 即按jdk1.4的语法,需要将一个数组作为参数传递给invoke方法时,
 数组中的每个元素分别对应被调用方法中的一个参数,所以,
 调用charAt方法的代码也可以用Jdk1.4改写为
 charAt.invoke(“str”, new Object[]{1})形式。

11.用反射方式调用某个类中的main方法。
 目标:
 写一个程序,这个程序能够根据用户提供的类名,去执行该类中的main方法。用普通方式调完后,大家要明白为什么要用反射方式去调啊?
 问题:
 启动Java程序的main方法的参数是一个字符串数组,即public static void main(String[] args),通过反射方式来调用这个main方法时,如何为invoke方法传递参数呢?按jdk1.5的语法,整个数组是一个参数,而按jdk1.4的语法,数组中的每个元素对应一个参数,当把一个字符串数组作为参数传递给invoke方法时,javac会到底按照哪种语法进行处理呢?jdk1.5肯定要兼容jdk1.4的语法,会按jdk1.4的语法进行处理,即把数组打散成为若干个单独的参数。所以,在给main方法传递参数时,不能使用代码mainMethod.invoke(null,new String[]{“xxx”}),javac只把它当作jdk1.4的语法进行理解,而不把它当作jdk1.5的语法解释,因此会出现参数类型不对的问题。
 解决办法:
 mainMethod.invoke(null,new Object[]{new String[]{"xxx"}});
 mainMethod.invoke(null,(Object)new String[]{"xxx"}); ,编译器会作特殊处理,编译时不把参数当作数组看待,也就不会数组打散成若干个参数了

12.数组的反射。
 数组反射之后的类是有名字的例如:[I
     [Ljava.lang.String;
     [Ljava.lang.Object;
     [[I
 他们的父类都是class java.lang.Object
 用发射取出数组内容:
  Array里面的方法:Array.get(数组对象,index);
   
  先把他们变为结合:Arrays.asList(数组对象);

 老师说数组的类型没办法确定,但是我认为可以直接获取。(老师讲错了)

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

13.hashCode分析
 a.通常来说,一个类的两个实例对象用equals()方法比较的结果相等时,他们的哈希码也必须相等,
 但反之则不成立。例如:字符串"BB"和"Aa"的equals方法比较不等,但他们的hashCode方法返回值却相等。
     ----->所以我认为HashSet判断其是否为同一个值会先用equals,如果相同再用hashCode方法判断,都相同则为一个对象,
    就会替代。
 b.当一个对象被存储进HashSet集合中以后,就不能修改这个对象中的那些参与计算哈希值的字段了,否则,对象修改后的
 哈希值与最初存储进HashSet集合中时的哈希值就不同了,那么即使使用contains方法使用该对象的当前引用作为参数去HashSet集合
 中检索,也将返回找不到对象的结果,这也会导致无法从HashSet集合中单独删除当前对象,从而造成内存泄露。
     ------>当对象加入集合之后,而对象中参与hashcode运算的字段进行修改的话,那么集合中将无法删除此对象,
     不过依旧可以遍历出来,出现的问题是不能remove,会出现内出泄露问题。
总结:1.判断相同的顺序:先hashCode再equals,equals不同的对象的hashCode可能会相同,因为hashCode毕竟不是全局唯一值,只是确保此类对象的唯一。
????有个问题:为什么要hashCode值。仅仅是为了快速超找有没有相同hashCode值么,说不通,因为相同值会先equals再hashCode。
      2.修改hashCode,或者参与hashCode运算的字段会出现内存泄露。
      3.我认为有可能是存入集合的时候先用hashCode判断,再用equals判断,这样就会快很多,然后再将此元素的hashCode注册到这个集合中,
      那么在删除的时候,直接用开始的hashCode寻找此元素,就会找不到,删除不了,
      遍历的时候不是用的这个原理,用的是迭代器。
这里可以答内存泄露。

14.反射的作用->实现框架功能。
 框架调用我写的类,我的类再调用工具类。
 可以先有框架,再有我的类。
 框架可以先调用我没有些的类。

   设置只读properties,我们放在执行类的兄弟位置,
   再使用类加载器加载此文件,那样eclipse就会将文件
   copy到.class文件区域。
   类名.class.getClassLoader().getResourceAsStream(包名(不要以"/"开头)+"config.properties");
   改良版:类名.class.getResourceAsStream("config.properties");// 其实内部也调用的是此类类加载器。

15.内省--->了解JavaBean
 JavaBean是一种特殊的Java类,主要用于传递数据信息,
 这种java类中的方法主要用于访问私有的字段,且方法名符合某种命名规则。
 如果要在两个模块之间传递多个信息,可以将这些信息封装到一个JavaBean中,
 这种JavaBean的实例对象通常称之为值对象(Value Object,简称VO)。
 这些信息在类中用私有字段来存储,如果读取或设置这些字段的值,
 则需要通过一些相应的方法来访问,大家觉得这些方法的名称叫什么好呢?
 JavaBean的属性是根据其中的setter和getter方法来确定的,
 而不是根据其中的成员变量。如果方法名为setId,中文意思即为设置id,
 至于你把它存到哪个变量上,用管吗?如果方法名为getId,
 中文意思即为获取id,至于你从哪个变量上取,用管吗?去掉set前缀,
 剩余部分就是属性名,如果剩余部分的第二个字母是小写的,则把剩余部分的首字母改成小的。
 setId()的属性名->id
 isLast()的属性名->last
 setCPU()的属性名是什么?->CPU
 getUPS()的属性名是什么?->UPS
 总之,一个类被当作javaBean使用时,JavaBean的属性是根据方法名推断出来的,它根本看不到java类内部的成员变量。

 一个符合JavaBean特点的类可以当作普通类一样进行使用,但把它当JavaBean用肯定需要带来一些额外的好处,我们才会去了解和应用JavaBean!好处如下:
 在Java EE开发中,经常要使用到JavaBean。很多环境就要求按JavaBean方式进行操作,别人都这么用和要求这么做,那你就没什么挑选的余地!
 JDK中提供了对JavaBean进行操作的一些API,这套API就称为内省。如果要你自己去通过getX方法来访问私有的x,怎么做,有一定难度吧?用内省这套api操作JavaBean比用普通类的方式更方便。

java7的新特性:switch的范围变成了所有的,
       map集合更方便了

16.注解Annotation(很重要)---是一种趋势
 总结:
 注解相当于一种标记,在程序中加了注解就等于为程序打上了某种标记,
 没加,则等于没有某种标记,以后,javac编译器,开发工具和其他程序
 可以用反射来了解你的类及各种元素上有无何种标记,看你有什么标记,就去干相应的事。
 
 标记可以加在包,类,字段,方法,方法的参数以及局部变量上。
 看java.lang包,可看到JDK中提供的最基本的annotation。
 Override 
 Deprecated
 SupperssWarnings

纠正:class文件并不是字节码,字节码是指class文件被加载到内存之后的二进制数据。

17.泛型

泛型中的?通配符

自定义泛型方法:只要在返回值前面加一个类型说明<T>即可。

自定义泛型类:只要在class后面添加一个类型说明<T>

静态方法的泛型是不能采用泛型类中的普通方法加泛型参数,必须自己在自己的返回类型之前自己加单独的泛型参数,
此泛型跟类泛型是不同的。


18.dao
 data access object数据访问对象
 crud  create read(retrieve) update delete
 一般有的方法:1.添加用户
        2.按索引删除
        3.按对象删除
        4.跟新(覆盖)对象
        5.按索引查询
        6.按条件查询,返回一个Set集合(传入要查询的条件即可)
        7.按照名字查找

19.得到某个类型的泛型:(用反射的知识,从hibernate源代码得到的)
 只能得到某个方法,其参数的形参。
 a.得到方法:类名.class.getMethod("方法名",参数.class)
 b.方法的类型参数: Type[] types = 方法.getGenericParameterTypes();
 c.第1个参数 types[0]
 d.得到实际化的类型参数 pType.getActualTypeArguments[0];

20.类加载器
系统默认的三个主要类加载器,每个负责加载特定位置的类:
BootStrap:JRE/lib/rt.jar
ExtClassLoader:JRE/lib/ext/*.jar
AppClassLoader:CLASSPATH指定的所有jar或目录

BootStrap内置在JVM上,而后面两个的本质均为类

类加载器的委托机制:
a.可以直接调用ClassLoader.loadClass()方法来指定某个类加载器去加载某个类。
b.如果类A中引用了类B,Java虚拟机将使用加载类A的类装载器来加载类B。
c.类加载器加载时,是委托给最上级从上往下加载。

21.模板方法设计模式

父类

子类1(自己干)

子类2(自己干)


22.代理(没理解透彻)(代理类是不是运用的是装饰模式??)

作用:
a.实现了AOP功能。
 AOP:Aspect oriented program
 交叉业务的编程问题就是面向方面编程。
 AOP的目标就是要使交叉业务模块化。可以采用将切面代码移动到原始方法的周围,
 这与直接在方法中编写切面代码的运行效果是一样的。
b.可以添加新功能


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

 

 

------- android培训、java培训、期待与您交流! ----------
原创粉丝点击