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

11 篇文章 0 订阅
1 篇文章 0 订阅
---------------------- 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);      //true
Integer 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> TYPE
System.out.println(int.class== Integer.TYPE);
                   //false
System.out.println(int[].class.isPrimitive());
//true
System.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
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值