【黑马程序员】 java笔记——基础加强

来源:互联网 发布:淘宝一元包邮 编辑:程序博客网 时间:2024/05/21 02:35
---------------------- ASP.Net+Android+IOS开发、.Net培训、期待与您交流! ----------------------

Java基础加强学习

1.      了解IDE

IDE其实就是集成开发环境。

2.      静态导入

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

import Static语句导入一个类中的某个静态方法或者所有的静态方法。

         //直接导入方法

Import staticjava.lang.Math.max;

//静态类下的方法都导入

Import staticjava.lang.Math.*;

3.      可变参数

主要涉及到的是方法覆盖和方法重载。

一个方法接收的参数个数不固定,例如:

System.out.println(add(2,3,4));

System.out.println(add(2,3,4,5));

Overrideoverload的区别:

Overload是重载,同一个函数可以有不同的参数列表。

Override是覆写父类的方法。

可变参数的特点:

只能出现在参数列表的最后;

…位于变量类型和变量名之间,前后空格可选;

调用可变参数的方法时,编译器为该可变参数隐含创建一个数组,在方法体中以数组的形式访问可变参数。

示例:

class VariableArgs{        public static int add(int x, int ... args)        {                   //把args当作int数组就可以了                   int sum = x;                   for(int a:args)                   {                           sum += a;                   }                   return sum;        }        public static void main(String[] args)        {                   System.out.println(add(1,2,3,4,5,6));        }}

4.      增强for循环

增强for循环的语法格式:

fortype 变量名:集合变量名)

{}

注意事项:

1.迭代变量必须在{}中定义。

2.集合变量可以是数组或实现了Iterable接口的集合类。

举例:

public Static int add(int x,int…… args){                int sum=x;                for(int arg:args)//此处就是增强for循环的格式                {                       sum+=sum;                }               return sum;}

5.      基本数据类型和自动装箱与自动拆箱

自动装箱

Integer num1=12

自动拆箱:

system.out.println(num1+12)

基本数据类型的对象缓存:

  Inter num1=12;  Inter num2=12;  System.out.println(num1=num2); Integer i1 = 5;Integer i2 = 5;System.out.println(i1==i2);      //trueInteger i3 = 128;Integer i4 = 128;System.out.println(i3 == i4);    //false

Java将小于一个字节的数字(-128127)放在内存中常驻。而对于大于一个字节的才在堆中创建。(python中也用到此技术)

享元模式(flyweight

多个小的对象,内容/属性大部分相同。可以将其统一设计为一个对象,相同的部分作为内部状态,不相同作为外部状态内容。其他不同的部分通过参数传入来设置。

Integer.valueOf(int)          //int显式得转为Integer

Integer.valueOf(5) == Integer.valueOf(5)              //true

6.      享元模式:flyweight pattern

简而言之就是共享物件,用来尽可能减少内存的使用量。

7.枚举

 什么是枚举?

 枚举是一种特殊的类。

 枚举一般是结合内部类出现的。同时枚举一般是用来表示那些确定的元素。比如星期几,性别等。枚举的对象是确定的,类或者方法调用不能创建新的,只能调用枚举类中已经存在的。

枚举就是要让某个类型的变量的取值只能为若干个固定值中的一个,否则,编译器就会报错;枚举可以让编译器在编译时就可以控制源程序中填写的非法值,普通变量的方式在开发阶段无法实现这一目标。

用普通类如何实现枚举功能,定义一个Weekday的类来模拟枚举功能

  私有的构造方法:

  每个元素分别用一个公有的静态成员变量表示

  可以由若干个公有方法或抽象方法,例如:要提供nextDay方法必须是抽象的

 采用抽象方法定义nextDay将大量的if else语句转移成了一个个独立的类(使用内部类)

 枚举的基本应用:

  举例:定义一个WeekDay的枚举

  扩展:枚举类得values.valueOf.name.toString.final等方法

总结:枚举是一种特殊的类,其中的每个元素都是该类的一个实例对象。例如可以调用WeekDay.SUN.getClass.getNameWeekDay.getClass.getName

枚举就相当于一个类,其中也可以定义构造方法,成员变量,普通方法和抽象方法

枚举元素必须位于枚举体中的最开始部分,枚举元素列表的后要有分号与其他成员分隔。把枚举中的成员方法或变量等放在枚举元素的前面,编译器报告错误。

带构造方法的枚举

构造方法必须定义成私有的

如果有多个构造方法,该如何选择哪个构造方法?

看元素初始化了MON()和MON1)调用不同的构造方法

枚举元素MONMON()的效果一样,都是调用默认的构造方法

带方法的枚举

    定义枚举trafficLamp

    实现普通的next方法

实现抽象的next方法:每个元素分别是由枚举类得子类来生成的实例对象,这些子类采用类似内部类的方式进行定义

增加上表示时间的构造方法

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

name()    //得到枚举值的名称

ordinal()  //得到枚举值在枚举声明中的位置

static EnumClass valueOf(String name);          //得到枚举名称为name的枚举值

static int[] values();                             //获得枚举对应的所有值组成的数组。

枚举类型在switch中不需要枚举名,只需要枚举值:

Weekday w = Weekday.MON;switch(w){        case(MON):                   …                   Break;……}

带有构造器的枚举

public enum WeekDay{/* 元素相等于静态的成员,没有括号的时候调用默认构造方法,也可以指定调用其他构造函数。*/        SUN(0),MON(1),TUE(2),WED(3),THI(4),FRI(5),SAT(6);        //元素列表必须在枚举类最前面。        //构造函数必须是私有的。         private WeekDay(int day)        {}}

带有抽象方法的枚举

内部类有四种访问权限,而普通的类只有public和包访问权限。

public class Weekday1{        public static void main(String args[]){                   //调用父类有参数的构造方法:                   new Date(300){};        }         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文件。

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

7.      反射

反射的基石:Class

Class-à代表Java中各个java类,描述java类的相关属性:类名/父类/所在包等等

Class类对象包含其他类的字节码信息。每个类对应一个字节码文件。

Date.class                 //得到Date类字节码

对象.getClass();      //得到对象所属类的字节码

Class.forName(java.lang.String);                  //得到指定类的字节码

其工作情况分两种:已载入内存的字节码和未载入内存的字节码

前者可以直接获得内存中的字节码,后者则会调用类加载器加载类,再获得其类字节码。

上面就是三种获得类字节码的方法,只要是同一个类,那么得到的最终是同一个字节码。

其中反射的话通常是用Class.forName方式,因为运行时不知道类名。

Class.forName还会抛出ClassNotFoundException.

9个预定义的Class对象(一开始就载入虚拟机):8个基本数据类型和void

示例:

publicclass ReflectTest{         public static void main(String[] args)throws Exception         {                   String str = "123";                   Class cls1 = str.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());                   //false                   System.out.println(int.class== Integer.class);        //true:Integer:public static finalClass<Integer> TYPESystem.out.println(int.class== Integer.TYPE);                   //falseSystem.out.println(int[].class.isPrimitive());//trueSystem.out.println(int[].class.isArray());         }}

  什么是反射?

  反射就是把java类中的各种成分映射成相应的java类。

如何得到各个字节码对应的实例对象(class类型)

  1.类名.class,例如:System.class

  2.对象.getclass(),例如:newDate().getclass();

 3.class.forName(“类名”),例如:class.forName("java.util.Date");

Constructor

  1.得到某一个类所有的构造方法:

  例子:Constructor[]constructor=Class.forName(“java.lang.string”).getConstructor

  2.得到某一个构造方法:

   例子:Constructorconstructor=

Class.forName(“java.lang.String”).getConstructors(StringBuffer.class)

获得方法时要用到类型 

3.创建实例对象:

     一般方式:Stringstr=new Stringnew StringBuffer(“abc”));

     反射方式:Stringstr=StringConstructor.newInstance(new String Buffer("ABC");

     调用获得的方法时要用到上面相同类型的实例对象。

Class.newInstance()方法:

例子:String obj = class.forName(java.lang.String)newInstance();

该方法内部先得到默认的构造方法,然后用该构造方法创建实例对象

该方法内部的具体代码是怎么写的?用到了缓存机制来保存默认构造方法的实例对象。

Field类反射

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

需求:将任意一个对象中的所有String类型的成员变量所对应的字符串内容中的“b”改成“a”。

 字节码的比较,使用 = =,不要使用equals;(因为这里只是一份字节码,没有第二份,所以不用equals

代码:

 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());   //记住1.强转 2.参数类型必须一致 //Constructor类反射 Constructor constructor = String.class.getConstructor(StringBuffer.class); String str2 = (String)constructor.newInstance(newStringBuffer("abcd")); System.out.println(str2.charAt(3)); //Field类反射  //field不是对象身上的变量,而是类上的,要用它去取某个对象身上的值 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)); changeStringValue(pt1); System.out.println(pt1); //str1.charAt(1); Method methodCharAt = String.class.getMethod("charAt",int.class); System.out.println(methodCharAt.invoke(str1, 1)); } private static void changeStringValue(Objectobj) throws IllegalArgumentException, IllegalAccessException { 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);   }  } }

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

  得到类中的某一个方法:

   例子:MethodcharAt=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没有可变参数,因此invoke中使用Object数组作为参数。

JDK1.5向下兼容

示例:

import java.lang.reflect.*;class TestArgs{        public static void main(String[] args)        {                  for(String str: args)                   {                            System.out.println(str);                   }        }}public class ReflectTest{        public static void main(String[] args) throws Exception        {                   //TestArgs.main(newString[]{"111","222"});                   //String startClassName =args[0];                   Method mainMethod =Class.forName(args[0]).getMethod("main",String[].class);                  //编译报错,mainMethod.invoke(null, newString[]{"111","222","333"});                   //一个Object数组,只有一个元素,这个元素是一个String[]数组                   mainMethod.invoke(null, newObject[]{new String[]{"111","222","333"}});                   //跟编译器打招呼:我这个String[]组你就当作一个Object得了。                   mainMethod.invoke(null,(Object)new String[]{"111","222","333"});        }}

当使用mainMethod.invoke(null, newString[]{"111","222","333"});时,java编译器编译报错,原因是JDK1.4中有invoke(Object[])的方法。为了向下兼容,JDK1.5newString[]{"111","222","333"}作为一个Object数组来处理,即分拆为三个参数传给函数。

警告最后一个参数使用了不准确的变量类型的 varargs 方法的非 varargs 调用;       mainMethod.invoke(null, new String[]{"111","222","333"}); 

对于 varargs 调用应使用多个Object分开,对于非 varargs 调用应使用 Object[], 这样也可以抑制此警告。

为此可以使用下面两个方法:

                   mainMethod.invoke(null, newObject[]{new String[]{"111","222","333"}});

                   mainMethod.invoke(null,(Object)new String[]{"111","222","333"});

9.数组的反射:

  具有相同维数和元素类型的数组属于同一类型,即具有相同的class实例对象。

  代表数组的class实例对象的getSuperClass()方法返回的父类为Object类对应的class

示例:

public class ReflectTest {      public static void main(String[] args)      {              int[] a1 = new int[3];              int[] a2 = new int[4];              int[][] a3 = new int[3][4];              String[] a4 = new String[4];              /*              System.out.println(a1.getClass()== a2.getClass());              System.out.println(a1.getClass()== a3.getClass());              System.out.println(a1.getClass()== a3.getClass());              */              //维数相同              //System.out.println(a1.getClass()== a2.getClass());              //维数不同连编译都报错了              //System.out.println(a1.getClass()== a3.getClass());              //输出为[[I              System.out.println(a3.getClass());      //compile error             System.out.println(a1.getClass() == a4.getClass());      }}

补充知识点:int不是一个Object,但是int[]是一个Object

     int[] a1 = new int[3];                   int[] a2 = new int[4];                   int[][] a3 = new int[3][4];                   String[] a4 = new String[4];                   System.out.println(a1.getClass().getSuperclass().getName());                   System.out.println(a4.getClass().getSuperclass().getName());                  Object aObj1 = a1;                   //a1是int数组,里面每个元素是int,不是objcet,不能够Object[]aObj2 = a1;                  Object aObj3 = a3;                   //a3是二维数组,里面每个成员是一维int数组。一维int数组是Object                  Object[] aObj4 = a3;                   //都是打印出   类名@hashCode                  System.out.println(a1);                  System.out.println(a3);                   System.out.println(a4);                   //使用asList打印。JDK1.4使用Object数组                   //由于a1是int数组。它不能当作一个Object数组,只能将其当作一个Object                   //所以打印Arrays.asList(a1)还是得到一个只有一个元素的List。//Arrays.asList接受可变参数,同时还有1.4以前的接受数组的asList                  System.out.println(Arrays.asList(a1));                   //a3转为一个List,每个元素是一位数组。                   System.out.println(Arrays.asList(a3));                   //字符数组则按预想结果处理                  System.out.println(Arrays.asList(a4));

打印结果:

java.lang.Object

java.lang.Object

[I@1a06f956

[[I@3fdb8a73

[Ljava.lang.String;@665ea4c5

[[I@1a06f956]

[[I@45edcd24, [I@7f371a59, [I@7aa30a4e]

[null, null, null, null]

  基本类型的一维数组可以被当作Object类型使用,不能当作Object[]类型使用;非基本类型的一维数组,即可以当作Object类型使用,不可以当作数组型使用。

利用反射打印数组示例:

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

 Arrays.aslist()方法处理int[]String[]的差异:

 Array工具类用于完成对数组的反射操作。

 

 HashSet类:就是采用哈希算法存取对象集合。

HashSet中不能包含相同对象的两个引用,但是可能包含包含两个哈希值相同的对象。

总结:HashSet在存储对象引用时,先计算hashCode(可以在复写的hashCode方法中输出来看看是不是),然后在内存中看看是否已经存在引用。如果不存在直接存入集合,否则比较这些hash值相同的对象,如果新对象和已有对象都不equals,才存入新对象。

 

  反射的作用:实现框架功能

框架调用自己编写的类。

框架不知道将会调用什么样的类,不能够new对象。

下面的方法通过读取配置文件className来决定运行时使用什么样的集合类型。

className文件中内容是:

className=java.util.ArrayList

public class RefelctTest2 {      public static void main(String[] args) throws Exception      {              InputStream is = newFileInputStream("className");              Properties perp = newProperties();              perp.load(is);              is.close();              String className =perp.getProperty("className");              //Collection coll = newArrayList();              Collection coll =(Collection)Class.forName(className).newInstance();              ReflectPoint rpt1 = newReflectPoint(3,4);              ReflectPoint rpt2 = newReflectPoint(3,4);              ReflectPoint rpt3 = newReflectPoint(9,9);              coll.add(rpt1);              coll.add(rpt2);              coll.add(rpt3);              coll.add(rpt3);              //根据配置文件中内容不同而不同:ArrayList是4,HashSet是2              System.out.println(coll.size());      }}


---------------------- ASP.Net+Android+IOS开发、.Net培训、期待与您交流! ----------------------详细请查看:http://edu.csdn.net
原创粉丝点击