传智播客 刘意_2015年Java基础视频-深入浅出精华版 笔记(day11~day17)(2016年2月28日17:39:18)

day11
1.Eclipse的基本使用
编译:
自动编译,在保存的那一刻(ctrl+s)帮你做好了(class文件出现在bin目录下)

 

2.Hierarchy 显示Java继承层次结构,选中类后F4

3.eclipse行号的显示与隐藏

4.D:字体大小及颜色
        a:Java代码区域的字体大小和颜色:
            window -- Preferences -- General -- Appearance -- Colors And Fonts -- Java修改 -- Java Edit Text Font
        b:控制台
            window -- Preferences -- General -- Appearance -- Colors And Fonts -- Debug -- Console font
        c:其他文件(比如文本文件txt)
            window -- Preferences -- General -- Appearance -- Colors And Fonts -- Basic -- Text Font
 
 
 
以上笔记总结
 
3:Eclipse空间的基本配置    
    A:程序的编译和运行的环境配置(一般不改)
        window -- Preferences -- Java
        编译环境:Compiler    默认选中的就是最高版本。
        运行环境:Installed JREs    默认会找你安装的那个JDK。建议配置了Java的环境变量。
        问题:
        低编译,高运行。可以。
        高编译,低运行。不可以。
            建议,编译和运行的版本一致。
 
    B:如何去掉默认注释?
        window -- Preferences -- Java -- Code Style -- Code Templates
        选择你不想要的内容,通过右边Edit编辑。
        注意:请只删除注释部分,不是注释部分的不要删除。
 
    C:行号的显示和隐藏
        显示:在代码区域的最左边的空白区域,右键 -- Show Line Numbers即可。
        隐藏:把上面的动作再做一次。
 
    D:字体大小及颜色
        a:Java代码区域的字体大小和颜色:
            window -- Preferences -- General -- Appearance -- Colors And Fonts -- Java修改 -- Java Edit Text Font
        b:控制台
            window -- Preferences -- General -- Appearance -- Colors And Fonts -- Debug -- Console font
        c:其他文件
            window -- Preferences -- General -- Appearance -- Colors And Fonts -- Basic -- Text Font
 
    E:窗体给弄乱了,怎么办?
        window -- Reset Perspective(eclipse3.7)
         window --Perspective---Reset Perspective(eclipse4.5)
 
    F:控制台找不到了,怎么办?
        Window--Show View—Console
 
eclipse快捷键
4.alt+/

 

5.
 
 * 常用快捷键
 * 1:格式化  ctrl+shift+f
 * 2:导入包  ctrl+shift+o
 *         如果该类仅仅在一个包中有,就自己显示了
 *         如果该类在多个包中有,会弹出一个框框供你选择
 * 3:注释  
 *         单行:注释 ctrl+/,取消注释再来一次。
 *         多行:ctrl+shift+/,ctrl+shift+\
 * 4:代码上下移动 
 *         选中代码alt+上/下箭头
 * 5:查看源码
 *         选中类名(F3或者Ctrl+鼠标点击)
 
导包
查看源码
6.自动生成构造方法
    a:无参构造方法 在代码区域右键--source--Generate Constructors from Superclass
    b:带参构造方法 在代码区域右键--source--Generate Constructors using fields.. -- finish
 
自动生成get/set方法
    在代码区域右键--source--Generate Getters and Setters...
对应的快捷键方法
如下图
 
即:Alt+Shift+S+c  :Generate Constructors from Superclass
    Alt+Shift+S+o  :Generate Constructors using Fields
     Alt+Shift+S+r  :Generate Getters and Setters
 

7.继承抽象类,或者实现接口

  a:以前做法 先写类,然后在类中在去继承类或者实现接口

  b:现在做法 在创建类的时候,选择要继承的类或者实现的接口。

  Object是所有类的父类,所有类都直接或者间接的继承自Object。

 

看到Override说说这是什么,有什么用。(起注解的作用)

8.eclipse制作帮助文档
编写源程序(设计接口,抽象类,具体类案例)
针对源程序添加文档注释
选中项目--右键--Export--Java--Javadoc—Finish
 
9.jar包
jar是什么?
jar是多个class文件的压缩包。
jar有什么用?
用别人写好的东西
打jar包
选中项目--右键--Export--Java--Jar--自己指定一个路径和一个名称--Finish
使用jar包
复制到项目路径下(ctrl+c  ctrl+v)并添加至构建路径。(右键-Build Path)
 
//
jar包有什么用,怎么用?
a:用于把别人写好的东西,直接拿过来使用。
 
b:怎么用
(1)找到jar包。
(2)复制jar包,粘贴到要使用的项目路径下。
(3)把jar添加到构建路径。classpath。
选中jar包,右键Build path -- add to build path
(4)按照正常用法用就可以了。
 
在开发的时候,很多常见的功能,别人都会做好了,我们只需要导入别人的jar包即可。
比如说,上传文件,下载文件,数据分页等功能。
 
10.几个小问题
如何查看项目所在路径
选中 -- 右键 -- Properties -- Resource -- Location
导入项目要注意的问题
项目区域中不可能出现同名的项目(新建或者导入)
自己随意建立的文件夹是不能作为项目导入的
修改项目问题
不要随意修改项目名称
如果真要修改,不要忘记了配置文件.project中的
<name>把这里改为你改后的名称</name>
 
11.eclipse中代码的高级(Debug)调试
    作用:
        调试程序
        查看程序执行流程
 
    如何查看程序执行流程
        要想看程序流程,就必须设置断点。
 
        什么是断点:
            就是一个标记,从哪里开始。
 
        如何设置断点:
            你想看哪里的程序,你就在那个有效程序的左边双击即可。
 
        在哪里设置断点:
            哪里不会点哪里。
            目前:我们就在每个方法的第一条有效语句上都加。
 
        如何运行设置断点后的程序:
            右键 -- Debug as -- Java Application
 
        看哪些地方:
            Debug:断点测试的地方
                在这个地方,记住F6,或者点击也可以。一次看一行的执行过程。
          Variables:查看程序的变量变化
            ForDemo:被查看的源文件
            Console:控制台
 
        如何去断点:
            a:再次双击即可
            b:找到Debug视图,Variables界面,找到Breakpoints,并点击,然后看到所有的断点,最后点击那个双叉。

个人补充:
    eclipse写注释方法:/* + 敲回车键(enter)
    eclipse写文档注释方法:/** + 敲回车键(enter)
 
 
12.Object类
Object:类 Object 是类层次结构的根类。每个类都使用 Object 作为超类。
 * 每个类都直接或者间接的继承自Object类。
 * 
 * Object类的方法:
 *         public int hashCode():返回该对象的哈希码值。
 *             注意:哈希值是根据哈希算法计算出来的一个值,这个值和地址值有关,但是不是实际地址值。
 *                        你可以理解为地址值。
 * 
13Object类的Class
.public final Class getClass():返回此 Object 的运行时类
 *            Class类的方法:
 *                public String getName():以 String 的形式返回此 Class 对象所表示的实体
 
用法
 
        Student s = new Student();
 
        Class c = s.getClass();
        String str = c.getName();
        System.out.println(str);
 
        //链式编程
        String str2 = s.getClass().getName();
        System.out.println(str2);
 
输出:
cn.itcast_01.Student
cn.itcast_01.Student
 
14.Object类的toString
public String toString():返回该对象的字符串表示。
 * 
 * Integer类下的一个静态方法:
 *         public static String toHexString(int i):把一个整数转成一个十六进制表示的字符串
 * 
 * 这个信息的组成就是这样,但是这个信息是没有任何意义的。所以,建议所有子类都重写该方法。
 * 怎么重写呢?
 *         把该类的所有成员变量值组成返回即可。
 * 重写的最终版方案就是自动生成toString()方法。
 * 
 * 注意:
 *      直接输出一个对象的名称,其实就是调用该对象的toString()方法。

 

15.Object类的equals
String的equals()方法是重写自Object类的,比较的是字符串的内容是否相同
 
 
equals:
 *         引用类型:默认情况下,比较的是地址值。
 *         不过,我们可以根据情况自己重写该方法。一般重写都是自动生成,比较对象的成员变量值是否相同
 
16.Object类的clone
@Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
Cloneable:此类实现了 Cloneable 接口,以指示 Object.clone() 方法可以合法地对该类实例进行按字段复制。 
这个接口是标记接口(无方法),告诉我们实现该接口的类就可以实现对象的复制了。
public class Student implements Cloneable {
……
}
 
补充笔记
getClass() 返回对象的字节码文件对象,反射中会详细讲解
两个注意问题;
        A:直接输出一个对象名称,其实默认调用了该对象的toString()方法。
        B:面试题 
            ==和equals()的区别?
            A:==
                基本类型:比较的是值是否相同
                引用类型:比较的是地址值是否相同
            B:equals()
                只能比较引用类型。默认情况下,比较的是地址值是否相同。
                但是,我们可以根据自己的需要重写该方法。
 
day12
1.Scanner
Scanner类:

一个可以使用正则表达式来解析基本类型和字符串的简单文本扫描器。

常用的两个方法:
 *         public int nextInt():获取一个int类型的值
 *         public String nextLine():获取一个String类型的值
 
// 先获取一个int值,在获取一个字符串
        // int a = sc.nextInt();
        // String s2 = sc.nextLine();
        // System.out.println("a:" + a + ",s2:" + s2);
        // System.out.println("-------------------");
如上的代码所示,出现问题了:
 *         先获取一个数值,在获取一个字符串,会出现问题。
 *         主要原因:就是那个换行符号的问题。
 
如何解决呢?
 *        方案 A:先获取一个数值后,再创建一个新的键盘录入对象获取字符串
 *        方案 B:把所有的数据都先按照字符串获取,然后要什么,你就对应的转换为什么。(涉及字符串转化为int)
        推荐方案B
方案A代码如下
        int a = sc.nextInt();
        Scanner sc2 = new Scanner(System.in);
        String s = sc2.nextLine();
        System.out.println("a:" + a + ",s:" + s);
2.String类(最常见,重要)
字符串:就是由多个字符组成的一串数据。也可以看成是一个字符数组。
 * 通过查看API,我们可以知道
 *         A:字符串字面值"abc"也可以看成是一个字符串对象。
 *         B:字符串是常量,一旦被赋值,就不能被改变。
3.String类的构造方法
 
 * 构造方法:
          public String():空构造
          public String(byte[] bytes):把字节数组转成字符串
         public String(byte[] bytes,int index,int length):把字节数组的一部分转成字符串
         public String(char[] value):把字符数组转成字符串
         public String(char[] value,int index,int count):把字符数组的一部分转成字符串
         public String(String original):把字符串常量值转成字符串
 
  字符串的方法:
       public int length():返回此字符串的长度。
4.字符串是常量,一旦被赋值,就不能被改变。-----的理解
 
5.一个面试题
String s = new String(“hello”)和String s = “hello”;的区别?
有。前者会创建2个对象,后者创建1个对象。
背景知识:==:比较引用类型比较的是地址值是否相同
  equals:比较引用类型默认也是比较地址值是否相同,而String类重写了equals()方法,比较的是内容是否相同。
测试代码
public static void main(String[] args) {
        String s1 = new String("hello");
        String s2 = "hello";
 
        System.out.println(s1 == s2);// false
        System.out.println(s1.equals(s2));// true
    }
内存图解
注意字符串常量值
 
6.又一个面试题
看程序写结果
public class StringDemo3 {
    public static void main(String[] args) {
        String s1 = new String("hello");
        String s2 = new String("hello");
        System.out.println(s1 == s2);// false
        System.out.println(s1.equals(s2));// true
 
        String s3 = new String("hello");
        String s4 = "hello";
        System.out.println(s3 == s4);// false
        System.out.println(s3.equals(s4));// true
 
        String s5 = "hello";
        String s6 = "hello";
        System.out.println(s5 == s6);// true
        System.out.println(s5.equals(s6));// true
    }
}
7.再一个面试题
看程序写结果
public class StringDemo4 {
    public static void main(String[] args) {
        String s1 = "hello";
        String s2 = "world";
        String s3 = "helloworld";
        System.out.println(s3 == s1 + s2);// false
        System.out.println(s3.equals((s1 + s2)));// true
 
        System.out.println(s3 == "hello" + "world");// false 这个我们错了,应该是true
        System.out.println(s3.equals("hello" + "world"));// true
 
        // 通过反编译(xjad)看源码,我们知道这里已经做好了处理。
        // System.out.println(s3 == "helloworld");
        // System.out.println(s3.equals("helloworld"));
    }
}
此题注意:
字符串如果是变量相加,先开空间,再拼接。
 字符串如果是常量相加,是先加,然后在常量池找,如果有就直接返回,否则,就创建。
 
8. String类的判断功能:
 * boolean equals(Object obj):比较字符串的内容是否相同,区分大小写
 * boolean equalsIgnoreCase(String str):比较字符串的内容是否相同,忽略大小写
 * boolean contains(String str):判断大字符串中是否包含小字符串
 * boolean startsWith(String str):判断字符串是否以某个指定的字符串开头
 * boolean endsWith(String str):判断字符串是否以某个指定的字符串结尾
 * boolean isEmpty():判断字符串是否为空。
 
字符串内容为空和字符串对象为空。
 *         String s = "";
 *         String s = null;
例子代码
String s1 ="hello";
System.out.println("isEmpty:" + s1.isEmpty());//false
 
        String s4 = "";
        String s5 = null;
        System.out.println("isEmpty:" + s4.isEmpty());//true
        // NullPointerException
        // s5对象都不存在,所以不能调用方法,空指针异常
        System.out.println("isEmpty:" + s5.isEmpty());
 
9.String类的获取功能
 * int length():获取字符串的长度。
 * char charAt(int index):获取指定索引位置的字符
 * int indexOf(int ch):返回指定字符在此字符串中第一次出现处的索引。
 *         为什么这里是int类型,而不是char类型?
 *         原因是:'a'和97其实都可以代表'a'
 * int indexOf(String str):返回指定字符串在此字符串中第一次出现处的索引。
 * int indexOf(int ch,int fromIndex):返回指定字符在此字符串中从指定位置后第一次出现处的索引。
 * int indexOf(String str,int fromIndex):返回指定字符串在此字符串中从指定位置后第一次出现处的索引。
 * String substring(int start):从指定位置开始截取字符串,默认到末尾包含start这个索引
 * String substring(int start,int end):从指定位置开始到指定位置结束截取字符串。包括start索引但是不包end索引
10.字符串的遍历
for (int x = 0; x < s.length(); x++) {
            // char ch = s.charAt(x);
            // System.out.println(ch);
            // 仅仅是输出,我就直接输出了
            System.out.println(s.charAt(x));
        }
11.实例分析
写代码前先写需求思路
 
 1 需求:统计一个字符串中大写字母字符,小写字母字符,数字字符出现的次数。(不考虑其他字符)
 2  * 举例:
 3  *         "Hello123World"
 4  * 结果:
 5  *         大写字符:2个
 6  *         小写字符:8个
 7  *         数字字符:3个
 8  * 
 9  * 分析:
10  *         前提:字符串要存在
11  *         A:定义三个统计变量
12  *             bigCount=0
13  *             smallCount=0
14  *             numberCount=0
15  *         B:遍历字符串,得到每一个字符。
16  *             length()和charAt()结合
17  *         C:判断该字符到底是属于那种类型的
18  *             大:bigCount++
19  *             小:smallCount++
20  *             数字:numberCount++
21  * 
22  *             这道题目的难点就是如何判断某个字符是大的,还是小的,还是数字的。
23  *             ASCII码表:
24  *                 0    48
25  *                 A    65
26  *                 a    97
27  *             虽然,我们按照数字的这种比较是可以的,但是想多了,有比这还简单的
28  *                 char ch = s.charAt(x);
29  * 
30  *                 if(ch>='0' && ch<='9') numberCount++
31  *                 if(ch>='a' && ch<='z') smallCount++
32  *                 if(ch>='A' && ch<='Z') bigCount++
33  *        D:输出结果。
34  *
35  
36  */
37 public class StringTest2 {
38     public static void main(String[] args) {
39         //定义一个字符串
40         String s = "Hello123World";
41  
42         //定义三个统计变量
43         int bigCount = 0;
44         int smallCount = 0;
45         int numberCount = 0;
46  
47         //遍历字符串,得到每一个字符。
48         for(int x=0; x<s.length(); x++){
49             char ch = s.charAt(x);
50  
51             //判断该字符到底是属于那种类型的
52             if(ch>='a' && ch<='z'){
53                 smallCount++;
54             }else if(ch>='A' && ch<='Z'){
55                 bigCount++;
56             }else if(ch>='0' && ch<='9'){
57                 numberCount++;
58             }
59         }
60  
61         //输出结果。
62         System.out.println("大写字母"+bigCount+"个");
63         System.out.println("小写字母"+smallCount+"个");
64         System.out.println("数字"+numberCount+"个");
65     }
66 }

 

12.String的转换功能:
  byte[] getBytes():把字符串转换为字节数组。
  char[] toCharArray():把字符串转换为字符数组。
  static String valueOf(char[] chs):把字符数组转成字符串。
  static String valueOf(int i):把int类型的数据转成字符串。
          注意:String类的valueOf方法可以把任意类型的数据转成字符串。
 String toLowerCase():把字符串转成小写。
  String toUpperCase():把字符串转成大写。
  String concat(String str):把字符串拼接。
示例
String s = "JavaSE";
// byte[] getBytes():把字符串转换为字节数组。
        byte[] bys = s.getBytes();
        for (int x = 0; x < bys.length; x++) {
            System.out.println(bys[x]);
        }
        System.out.println("----------------");
 

        // char[] toCharArray():把字符串转换为字符数组。
        char[] chs = s.toCharArray();
        for (int x = 0; x < chs.length; x++) {
            System.out.println(chs[x]);
        }
        System.out.println("----------------");
 

        // static String valueOf(char[] chs):把字符数组转成字符串。
        String ss = String.valueOf(chs);
        System.out.println(ss);
        System.out.println("----------------");
 
        // static String valueOf(int i):把int类型的数据转成字符串。
        int i = 100;
        String sss = String.valueOf(i);
        System.out.println(sss);
        System.out.println("----------------");
// String concat(String str):把字符串拼接。
        String s1 = "hello";
        String s2 = "world";
        String s3 = s1 + s2;//常用
        String s4 = s1.concat(s2);//不常用
        System.out.println("s3:"+s3);
        System.out.println("s4:"+s4);
13.一个案例
 
/*
 * 需求:把一个字符串的首字母转成大写,其余为小写。(只考虑英文大小写字母字符)
 * 举例:
 *         helloWORLD
 * 结果:
 *         Helloworld
 * 
 * 分析:
 *         A:先获取第一个字符
 *         B:获取除了第一个字符以外的字符
 *         C:把A转成大写
 *         D:把B转成小写
 *         E:C拼接D
 */
public class StringTest {
    public static void main(String[] args) {
        // 定义一个字符串
        String s = "helloWORLD";
 
        // 先获取第一个字符
        String s1 = s.substring(0, 1);
        // 获取除了第一个字符以外的字符
        String s2 = s.substring(1);
        // 把A转成大写
        String s3 = s1.toUpperCase();
        // 把B转成小写
        String s4 = s2.toLowerCase();
        // C拼接D
        String s5 = s3.concat(s4);
        System.out.println(s5);
 
        // 优化后的代码
        // 链式编程
        String result = s.substring(0, 1).toUpperCase()
                .concat(s.substring(1).toLowerCase());
        System.out.println(result);
    }
}
 
14.String类的其他功能:
  
 替换功能:
  String replace(char old,char new)
  String replace(String old,String new)
 
  去除字符串两空格  (只可以去除前后的空格而不能去除中间的空格)
  String trim()
  
  按字典顺序比较两个字符串  
 int compareTo(String str)
 int compareToIgnoreCase(String str)
 
 
去除字符串两空格  (只可以去除前后的空格而不能去除中间的空格)
  String trim()
 
// 去除字符串两空格
        String s4 = " hello world  ";
        String s5 = s4.trim();
        System.out.println("s4:" + s4 + "---");
        System.out.println("s5:" + s5 + "---");
 
15.String类的compareTo方法的源码解析
问题引入
String s1 = "hello";
        String s2 = "hel";
        System.out.println(s1.compareTo(s2)); //输出为 2
解决:看源码(看compareTo)
hello与hel的字符串比较
 
解析:
  private final char value[];
 
    字符串会自动转换为一个字符数组。
 
  public int compareTo(String anotherString) {
          //this -- s1 -- "hello"
          //anotherString -- s2 -- "hel"
 
        int len1 = value.length; //this.value.length--s1.toCharArray().length--5
        int len2 = anotherString.value.length;//s2.value.length -- s2.toCharArray().length--3
        int lim = Math.min(len1, len2); //Math.min(5,3); -- lim=3;
        char v1[] = value; //s1.toCharArray()
        char v2[] = anotherString.value;
 
        //char v1[] = {'h','e','l','l','o'};
        //char v2[] = {'h','e','l'};
 
        int k = 0;
        while (k < lim) {
            char c1 = v1[k]; //c1='h','e','l'
            char c2 = v2[k]; //c2='h','e','l'
            if (c1 != c2) {
                return c1 - c2;
            }
            k++;
        }
        return len1 - len2; //5-3=2;
   }
 
   String s1 = "hello";
   String s2 = "hel";
   System.out.println(s1.compareTo(s2)); // 2
 
16.字符串反转
举例:键盘录入”abc”        
 * 输出结果:”cba”
 * 
 * 分析:
 *         A:键盘录入一个字符串
 *         B:定义一个新字符串
 *         C:倒着遍历字符串,得到每一个字符
 *             a:length()和charAt()结合
 *             b:把字符串转成字符数组
 *         D:用新字符串把每一个字符拼接起来
 *         E:输出新串
一种做法
===============================================
// 键盘录入一个字符串
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入一个字符串:");
        String line = sc.nextLine();
 
        /*
        // 定义一个新字符串
        String result = "";
 
        // 把字符串转成字符数组
        char[] chs = line.toCharArray();
 
        // 倒着遍历字符串,得到每一个字符
        for (int x = chs.length - 1; x >= 0; x--) {
            // 用新字符串把每一个字符拼接起来
            result += chs[x];  (字符自动转为字符串??)
        }
 
        // 输出新串
        System.out.println("反转后的结果是:" + result);
        */
=================================================
我的做法
System.out.println("请输入一个字符串:");
        Scanner sc = new Scanner(System.in);
        String s = sc.nextLine();
 
        char[] ch = s.toCharArray();
        char temp;
 
        for (int x = 0; x < (ch.length) / 2; x++) {
            temp = ch[x];
            ch[x] = ch[ch.length - 1 - x];
            ch[ch.length - 1 - x] = temp;
        }
 
        String s2 = String.valueOf(ch);
        System.out.println(s2);
===================================================
17.day12笔记补充
Scanner
需要注意的小问题
        A:同一个Scanner对象,先获取数值,再获取字符串会出现一个小问题。
        B:解决方案:
            a:重新定义一个Scanner对象
            b:把所有的数据都用字符串获取,然后再进行相应的转换
 
day13
1.StringBuffer
线程安全(多线程讲解)
 * 安全 -- 同步 -- 数据是安全的
 * 不安全 -- 不同步 -- 效率高一些
 * 安全和效率问题是永远困扰我们的问题。
 * 安全:医院的网站,银行网站
 * 效率:新闻网站,论坛之类的
 * 
 * StringBuffer:
 *         线程安全的可变字符串。
 * 
 * StringBuffer和String的区别?
 * 前者长度和内容可变,后者不可变。
 * 如果使用前者做字符串的拼接,不会浪费太多的资源。
2
2.StringBuffer的构造方法:
 *         public StringBuffer():无参构造方法(最常用,相当于造了一个水杯而没有装水)
 *        public StringBuffer(int capacity):指定容量的字符串缓冲区对象
 *        public StringBuffer(String str):指定字符串内容的字符串缓冲区对象
 
 
StringBuffer sb = new StringBuffer();
        System.out.println("sb:" + sb);
        System.out.println("sb.capacity():" + sb.capacity());//16
        System.out.println("sb.length():" + sb.length());//0
 
3.StringBuffer的方法:
 *        public int capacity():返回当前容量。    理论值(水杯最多可以装多少水)
 *        public int length():返回长度(字符数)。 实际值(实际上水杯有多少水)
4.StringBuffer的添加功能:
 * public StringBuffer append(String str):可以把任意类型数据添加到字符串缓冲区里面,并返回字符串缓冲区本身
 * 
 * public StringBuffer insert(int offset,String str):在指定位置把任意类型的数据插入到字符串缓冲区里面,并返回字符串缓冲区本身
 
 

5.StringBuffer的删除功能
 * public StringBuffer deleteCharAt(int index):删除指定位置的字符,并返回本身
 * public StringBuffer delete(int start,int end):删除从指定位置开始指定位置结束的内容,并返回本身(包括start不包括end)
 
        // 需求:我要删除所有的数据
        sb.delete(0, sb.length());
 
6.StringBuffer的替换功能:
 * public StringBuffer replace(int start,int end,String str):从start开始到end用str替换
7.StringBuffer的反转功能:(Stirng类没有)
 * public StringBuffer reverse()
 
8.StringBuffer的截取功能:注意返回值类型不再是StringBuffer本身了
 * public String substring(int start)
 * public String substring(int start,int end)
 
举例:
// 创建字符串缓冲区对象
        StringBuffer sb = new StringBuffer();
 
        // 添加元素
        sb.append("hello").append("world").append("java");
        System.out.println("sb:" + sb);
 
        // 截取功能
        // public String substring(int start)
        String s = sb.substring(5);
        System.out.println("s:" + s);
        System.out.println("sb:" + sb);
 
        // public String substring(int start,int end)
        String ss = sb.substring(5, 10);
        System.out.println("ss:" + ss);
        System.out.println("sb:" + sb);
9.StringBuffer和String的相互转换
为什么我们要讲解类之间的转换:
 * A -- B的转换
 * 我们把A转换为B,其实是为了使用B的功能。
 * B -- A的转换
 * 我们可能要的结果是A类型,所以还得转回来。
 * 
 * String和StringBuffer的相互转换?
 
 
===================================
public class StringBufferTest {
    public static void main(String[] args) {
        // String -- StringBuffer
        // 方式1:通过构造方法(推荐)
        StringBuffer sb = new StringBuffer(s);
        // 方式2:通过append()方法
        StringBuffer sb2 = new StringBuffer();
        sb2.append(s);
        System.out.println("sb:" + sb);
        System.out.println("sb2:" + sb2);
        System.out.println("---------------");
 
        // StringBuffer -- String
        StringBuffer buffer = new StringBuffer("java");
        // String(StringBuffer buffer)
        // 方式1:通过构造方法
        String str = new String(buffer);
        // 方式2:通过toString()方法(推荐)
        String str2 = buffer.toString();
        System.out.println("str:" + str);
        System.out.println("str2:" + str2);
    }
}
====================================
10.把数组拼接成一个字符串(用String和StringBuffer实现)
推荐用StringBuffer,因为没那么浪费空间
具体如下
public class StringBufferTest2 {
    public static void main(String[] args) {
        // 定义一个数组
        int[] arr = { 44, 33, 55, 11, 22 };
 
        // 定义功能
        // 方式1:用String做拼接的方式
        String s1 = arrayToString(arr);
        System.out.println("s1:" + s1);
 
        // 方式2:用StringBuffer做拼接的方式
        String s2 = arrayToString2(arr);
        System.out.println("s2:" + s2);
    }
 
    // 用StringBuffer做拼接的方式
    public static String arrayToString2(int[] arr) {
        StringBuffer sb = new StringBuffer();
 
        sb.append("[");
        for (int x = 0; x < arr.length; x++) {
            if (x == arr.length - 1) {
                sb.append(arr[x]);
            } else {
                sb.append(arr[x]).append(", ");
            }
        }
        sb.append("]");
 
        return sb.toString();
    }
 
    // 用String做拼接的方式
    public static String arrayToString(int[] arr) {
        String s = "";
 
        s += "[";
        for (int x = 0; x < arr.length; x++) {
            if (x == arr.length - 1) {
                s += arr[x];
            } else {
                s += arr[x];
                s += ", ";
            }
        }
        s += "]";
 
        return s;
    }
}
 
11.把字符串反转(String和StringBuffer)
 
import java.util.Scanner;
 
public class StringBufferTest3 {
    public static void main(String[] args) {
        // 键盘录入数据
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入数据:");
        String s = sc.nextLine();
 
        // 方式1:用String做拼接
        String s1 = myReverse(s);
        System.out.println("s1:" + s1);
        // 方式2:用StringBuffer的reverse()功能
        String s2 = myReverse2(s);
        System.out.println("s2:" + s2);
    }
 
    // 用StringBuffer的reverse()功能
    public static String myReverse2(String s) {
        // StringBuffer sb = new StringBuffer();
        // sb.append(s);
 
        // StringBuffer sb = new StringBuffer(s);
        // sb.reverse();
        // return sb.toString();
 
        // 简易版
        return new StringBuffer(s).reverse().toString();
    }
 
    // 用String做拼接
    public static String myReverse(String s) {
        String result = "";
 
        char[] chs = s.toCharArray();
        for (int x = chs.length - 1; x >= 0; x--) {
            // char ch = chs[x];
            // result += ch;
            result += chs[x];
        }
 
        return result;
    }
}
 
12.案例:判断一个字符串是否是对称字符串(String和StringBuffer实现)
例如"abc"不是对称字符串,"aba"、"abba"、"aaa"、"mnanm"是对称字符串
分析:
 *         判断一个字符串是否是对称的字符串,我只需要把
 *             第一个和最后一个比较
 *             第二个和倒数第二个比较
 *             ...
 *         比较的次数是长度除以2。
========================================
public class StringBufferTest4 {
    public static void main(String[] args) {
        // 创建键盘录入对象
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入一个字符串:");
        String s = sc.nextLine();
 
        // 一个一个的比较
        boolean b = isSame(s);
        System.out.println("b:" + b);
 
        //用字符串缓冲区的反转功能
        boolean b2 = isSame2(s);
        System.out.println("b2:"+b2);
    }
 
    public static boolean isSame2(String s) {
        return new StringBuffer(s).reverse().toString().equals(s);
    }
 
 
    // public static boolean isSame(String s) {
    // // 把字符串转成字符数组
    // char[] chs = s.toCharArray();
    //
    // for (int start = 0, end = chs.length - 1; start <= end; start++, end--) {
    // if (chs[start] != chs[end]) {
    // return false;
    // }
    // }
    //
    // return true;
    // }
 
    public static boolean isSame(String s) {
        boolean flag = true;
 
        // 把字符串转成字符数组
        char[] chs = s.toCharArray();
 
        for (int start = 0, end = chs.length - 1; start <= end; start++, end--) {
            if (chs[start] != chs[end]) {
                flag = false;
                break;
            }
        }
 
        return flag;
    }
}
======================================================
13.类 StringBuilder(since  JDK1.5)

(API)一个可变的字符序列。此类提供一个与 StringBuffer兼容的 API,但不保证同步(效率较高,安全性低)。该类被设计用作 StringBuffer

 的一个简易替换,用在字符串缓冲区被单个线程使用的时候(这种情况很普遍)。如果可能,建议优先采用该类,因为在大多数实现中,它比 StringBuffer 要快。

14.关于StringBuffer面试题

 

面试题:
 * 1:String,StringBuffer,StringBuilder的区别?
 * A:String内容不可变的,而StringBuffer,StringBuilder都是内容可变的。
 * B:StringBuffer同步的,数据安全,效率低;StringBuilder不同步的,数据不安全,效率高
 * 
 * 2:StringBuffer和数组的区别?
 * 二者都可以看出是一个容器,装其他的数据。
 * 但是呢,StringBuffer的数据最终是一个字符串数据
 * 而数组可以放置多种数据,但必须是同一种数据类型的。
 * 
 * 3:形式参数问题
 * String作为参数传递
 * StringBuffer作为参数传递 

 

 

 

形式参数:
 *         基本类型:形式参数的改变不影响实际参数
 *         引用类型:形式参数的改变直接影响实际参数
 * 
 * 注意:
 *         String作为参数传递,效果和基本类型作为参数传递是一样的。

 

(要用debug查看一下)

 

public class StringBufferDemo {
    public static void main(String[] args) {
        String s1 = "hello";
        String s2 = "world";
        System.out.println(s1 + "---" + s2);// hello---world
        change(s1, s2);
        System.out.println(s1 + "---" + s2);// hello---world
 
        StringBuffer sb1 = new StringBuffer("hello");
        StringBuffer sb2 = new StringBuffer("world");
        System.out.println(sb1 + "---" + sb2);// hello---world
        change(sb1, sb2);
        System.out.println(sb1 + "---" + sb2);// hello---worldworld
 
    }
 
    public static void change(StringBuffer sb1, StringBuffer sb2) {
        sb1 = sb2;
        sb2.append(sb1);
    }
 
    public static void change(String s1, String s2) {
        s1 = s2;
        s2 = s1 + s2;
    }
}
 
debug过程截图
 
 
 
 
 
 
 
 


 

字符串是一个特殊的引用类型,只能把它当作基本类型看  ,字符串例如"hello"看作常量
 
15.代码摘录:数组冒泡排序
===================================================
/*
 * 数组排序之冒泡排序:
 *         相邻元素两两比较,大的往后放,第一次完毕,最大值出现在了最大索引处
 */
public class ArrayDemo {
    public static void main(String[] args) {
        // 定义一个数组
        int[] arr = { 24, 69, 80, 57, 13 };
        System.out.println("排序前:");
        printArray(arr);
 
        /*
        // 第一次比较
        // arr.length - 1是为了防止数据越界
        // arr.length - 1 - 0是为了减少比较的次数
        for (int x = 0; x < arr.length - 1 - 0; x++) {
            if (arr[x] > arr[x + 1]) {
                int temp = arr[x];
                arr[x] = arr[x + 1];
                arr[x + 1] = temp;
            }
        }
        System.out.println("第一次比较后:");
        printArray(arr);
 
        // 第二次比较
        // arr.length - 1是为了防止数据越界
        // arr.length - 1 - 1是为了减少比较的次数
        for (int x = 0; x < arr.length - 1 - 1; x++) {
            if (arr[x] > arr[x + 1]) {
                int temp = arr[x];
                arr[x] = arr[x + 1];
                arr[x + 1] = temp;
            }
        }
        System.out.println("第二次比较后:");
        printArray(arr);
 
        // 第三次比较
        // arr.length - 1是为了防止数据越界
        // arr.length - 1 - 2是为了减少比较的次数
        for (int x = 0; x < arr.length - 1 - 2; x++) {
            if (arr[x] > arr[x + 1]) {
                int temp = arr[x];
                arr[x] = arr[x + 1];
                arr[x + 1] = temp;
            }
        }
        System.out.println("第三次比较后:");
        printArray(arr);
 
        // 第四次比较
        // arr.length - 1是为了防止数据越界
        // arr.length - 1 - 3是为了减少比较的次数
        for (int x = 0; x < arr.length - 1 - 3; x++) {
            if (arr[x] > arr[x + 1]) {
                int temp = arr[x];
                arr[x] = arr[x + 1];
                arr[x + 1] = temp;
            }
        }
        System.out.println("第四次比较后:");
        printArray(arr);
        */
 
        // 既然听懂了,那么上面的代码就是排序代码
        // 而上面的代码重复度太高了,所以用循环改进
        // for (int y = 0; y < 4; y++) {
        // for (int x = 0; x < arr.length - 1 - y; x++) {
        // if (arr[x] > arr[x + 1]) {
        // int temp = arr[x];
        // arr[x] = arr[x + 1];
        // arr[x + 1] = temp;
        // }
        // }
        // }
 
        /*
        // 由于我们知道比较的次数是数组长度-1次,所以改进最终版程序
        for (int x = 0; x < arr.length - 1; x++) {
            for (int y = 0; y < arr.length - 1 - x; y++) {
                if (arr[y] > arr[y + 1]) {
                    int temp = arr[y];
                    arr[y] = arr[y + 1];
                    arr[y + 1] = temp;
                }
            }
        }
        System.out.println("排序后:");
        printArray(arr);
        */
 
        //由于我可能有多个数组要排序,所以我要写成方法
        bubbleSort(arr);
        System.out.println("排序后:");
        printArray(arr);
    }
 
    //冒泡排序代码
    public static void bubbleSort(int[] arr){
        for (int x = 0; x < arr.length - 1; x++) {
            for (int y = 0; y < arr.length - 1 - x; y++) {
                if (arr[y] > arr[y + 1]) {
                    int temp = arr[y];
                    arr[y] = arr[y + 1];
                    arr[y + 1] = temp;
                }
            }
        }
    }
 
    // 遍历功能
    public static void printArray(int[] arr) {
        System.out.print("[");
        for (int x = 0; x < arr.length; x++) {
            if (x == arr.length - 1) {
                System.out.print(arr[x]);
            } else {
                System.out.print(arr[x] + ", ");
            }
        }
        System.out.println("]");
    }
}
============================================
数组高级冒泡排序原理图解
 
经整理 后的代码如下
public class BubbleTest {
    public static void main(String[] args) {
        int[] arr = { 24, 69, 80, 57, 13 };
        System.out.println("排序前:");
        printArray(arr);
        bubbleSort(arr);
        System.out.println("排序后:");
        printArray(arr);
    }
 
    // 打印数组,遍历功能
    public static void printArray(int[] arr) {
        System.out.print("[");
        for (int x = 0; x < arr.length; x++) {
            if (x == arr.length - 1) {
                System.out.print(arr[x]);
            } else {
                System.out.print(arr[x] + ",");
            }
        }
 
        System.out.println("]");
    }
 
    public static void bubbleSort(int[] arr) {
        for (int y = 0; y < arr.length - 1; y++) {
            for (int x = 0; x < arr.length - 1 - y; x++) {
                if (arr[x] > arr[x + 1]) {
                    int temp = arr[x];
                    arr[x] = arr[x + 1];
                    arr[x + 1] = temp;
                }
            }
        }
    }
 
}
 
16.代码摘录:数组选择排序
数组排序之选择排序:
 *         从0索引开始,依次和后面元素比较,小的往前放,第一次完毕,最小值出现在了最小索引处
 
public class ArrayDemo {
    public static void main(String[] args) {
        // 定义一个数组
        int[] arr = { 24, 69, 80, 57, 13 };
        System.out.println("排序前:");
        printArray(arr);
 
        /*
        // 第一次
        int x = 0;
        for (int y = x + 1; y < arr.length; y++) {
            if (arr[y] < arr[x]) {
                int temp = arr[x];
                arr[x] = arr[y];
                arr[y] = temp;
            }
        }
        System.out.println("第一次比较后:");
        printArray(arr);
 
        // 第二次
        x = 1;
        for (int y = x + 1; y < arr.length; y++) {
            if (arr[y] < arr[x]) {
                int temp = arr[x];
                arr[x] = arr[y];
                arr[y] = temp;
            }
        }
        System.out.println("第二次比较后:");
        printArray(arr);
 
        // 第三次
        x = 2;
        for (int y = x + 1; y < arr.length; y++) {
            if (arr[y] < arr[x]) {
                int temp = arr[x];
                arr[x] = arr[y];
                arr[y] = temp;
            }
        }
        System.out.println("第三次比较后:");
        printArray(arr);
 
        // 第四次
        x = 3;
        for (int y = x + 1; y < arr.length; y++) {
            if (arr[y] < arr[x]) {
                int temp = arr[x];
                arr[x] = arr[y];
                arr[y] = temp;
            }
        }
        System.out.println("第四次比较后:");
        printArray(arr);
        */
 
        /*
        //通过观察发现代码的重复度太高,所以用循环改进
        for(int x=0; x<arr.length-1; x++){
            for(int y=x+1; y<arr.length; y++){
                if(arr[y] <arr[x]){
                    int temp = arr[x];
                    arr[x] = arr[y];
                     arr[y] = temp;
                }
            }
        }
        System.out.println("排序后:");
        printArray(arr);
        */
 
        //用方法改进
        selectSort(arr);
        System.out.println("排序后:");
        printArray(arr);
 
    }
 
    public static void selectSort(int[] arr){
        for(int x=0; x<arr.length-1; x++){
            for(int y=x+1; y<arr.length; y++){
                if(arr[y] <arr[x]){
                    int temp = arr[x];
                    arr[x] = arr[y];
                     arr[y] = temp;
                }
            }
        }
    }
 
    // 遍历功能
    public static void printArray(int[] arr) {
        System.out.print("[");
        for (int x = 0; x < arr.length; x++) {
            if (x == arr.length - 1) {
                System.out.print(arr[x]);
            } else {
                System.out.print(arr[x] + ", ");
            }
        }
        System.out.println("]");
    }
}
17.二分查找
思路
 查找:
 *         基本查找:数组元素无序(从头找到尾)
 *         二分查找(折半查找):数组元素有序
 * 
 * 分析:
 *         A:定义最大索引,最小索引
 *         B:计算出中间索引
 *         C:拿中间索引的值和要查找的值进行比较
 *             相等:就返回当前的中间索引
 *             不相等:
 *                 大    左边找
 *                 小    右边找
 *         D:重新计算出中间索引
 *             大    左边找
 *                 max = mid - 1;
 *             小    右边找
 *                 min = mid + 1;
 *         E:回到B
 */
public class ArrayDemo {
    public static void main(String[] args) {
        //定义一个数组
        int[] arr = {11,22,33,44,55,66,77};
 
        //写功能实现
        int index = getIndex(arr, 33);
        System.out.println("index:"+index);
 
        //假如这个元素不存在后有什么现象呢?
        index = getIndex(arr, 333);
        System.out.println("index:"+index);
    }
 
    /*
     * 两个明确:
     * 返回值类型:int
     * 参数列表:int[] arr,int value
     */
    public static int getIndex(int[] arr,int value){
        //定义最大索引,最小索引
        int max = arr.length -1;
        int min = 0;
 
        //计算出中间索引
        int mid = (max +min)/2;
 
        //拿中间索引的值和要查找的值进行比较
        while(arr[mid] != value){
            if(arr[mid]>value){
                max = mid - 1;
            }else if(arr[mid]<value){
                min = mid + 1;
            }
 
            //加入判断
            if(min > max){
                return -1;
            }
 
            mid = (max +min)/2;
        }
 
        return mid;
    }
}
 
18.Arrays类  大多为静态方法
Arrays:针对数组进行操作的工具类。比如说排序和查找。
 * 1:public static String toString(int[] a) 把数组转成字符串
 * 2:public static void sort(int[] a) 对数组进行排序
 * 3:public static int binarySearch(int[] a,int key) 二分查找
示例
=======================================
public class ArraysDemo {
    public static void main(String[] args) {
        // 定义一个数组
        int[] arr = { 24, 69, 80, 57, 13 };
 
        // public static String toString(int[] a) 把数组转成字符串
        System.out.println("排序前:" + Arrays.toString(arr));
 
        // public static void sort(int[] a) 对数组进行排序
        Arrays.sort(arr);
        System.out.println("排序后:" + Arrays.toString(arr));
 
        // [13, 24, 57, 69, 80]
        // public static int binarySearch(int[] a,int key) 二分查找
        System.out.println("binarySearch:" + Arrays.binarySearch(arr, 57));
        System.out.println("binarySearch:" + Arrays.binarySearch(arr, 577));
    }
}
================================================
Arrays工具类的方法源码解析
public static String toString(int[] a)
public static void sort(int[] a) 底层是快速排序,知道就可以了。有空看,有问题再问我
public static int binarySearch(int[] a,int key)
 
开发原则:
    只要是对象,我们就要判断该对象是否为null。
 
int[] arr = { 24, 69, 80, 57, 13 };
System.out.println("排序前:" + Arrays.toString(arr));
 
public static String toString(int[] a) {
    //a -- arr -- { 24, 69, 80, 57, 13 }
 
    if (a == null)
        return "null"; //说明数组对象不存在
    int iMax = a.length - 1; //iMax=4;
    if (iMax == -1)
        return "[]"; //说明数组存在,但是没有元素。
 
    StringBuilder b = new StringBuilder();
    b.append('['); //"["
    for (int i = 0; ; i++) {
        b.append(a[i]); //"[24, 69, 80, 57, 13"
        if (i == iMax)
            //"[24, 69, 80, 57, 13]"
            return b.append(']').toString();
        b.append(", "); //"[24, 69, 80, 57, "
    }
}
-----------------------------------------------------
 
int[] arr = {13, 24, 57, 69, 80};
System.out.println("binarySearch:" + Arrays.binarySearch(arr, 577));
 
public static int binarySearch(int[] a, int key) {
    //a -- arr -- {13, 24, 57, 69, 80}
    //key -- 577
    return binarySearch0(a, 0, a.length, key);
}
 
private static int binarySearch0(int[] a, int fromIndex, int toIndex,
                                 int key) {
    //a -- arr --  {13, 24, 57, 69, 80}
    //fromIndex -- 0
    //toIndex -- 5
    //key -- 577(用一个不存在的数测试)                          
 
 
    int low = fromIndex; //low=0
    int high = toIndex - 1; //high=4
 
    while (low <= high) {
        int mid = (low + high) >>> 1; //>>> 无符号右移,相当于除以2    mid=2,mid=3,mid=4
        int midVal = a[mid]; //midVal=57,midVal=69,midVal=80
 
        if (midVal < key)
            low = mid + 1; //low=3,low=4,low=5
        else if (midVal > key)
            high = mid - 1;
        else
            return mid; // key found
    }
    return -(low + 1);  // key not found.
}
19.基本类型包装类概述
为了对基本数据类型进行更多的操作,更方便的操作,Java就针对每一种基本数据类型提供了对应的类类型。包装类类型。
 * byte             Byte
 * short            Short
 * int                Integer
 * long                Long
 * float            Float
 * double            Double
 * char                Character
 * boolean            Boolean
 * 
 * 用于基本数据类型与字符串之间的转换。
public class IntegerDemo {
    public static void main(String[] args) {
        // 不麻烦的就来了,冒号为查阅API信息
        // public static String toBinaryString(int i)
        System.out.println(Integer.toBinaryString(100));
        // public static String toOctalString(int i)
        System.out.println(Integer.toOctalString(100));
        // public static String toHexString(int i)
        System.out.println(Integer.toHexString(100));
 
        // public static final int MAX_VALUE
        System.out.println(Integer.MAX_VALUE);
        // public static final int MIN_VALUE
        System.out.println(Integer.MIN_VALUE);
    }
}
 
20.Integer的构造方法
两种方法
 * public Integer(int value)
 * public Integer(String s)
 *         注意:这个字符串必须是由数字字符组成
 */
public class IntegerDemo {
    public static void main(String[] args) {
        // 方式1
        int i = 100;
        Integer ii = new Integer(i);
        System.out.println("ii:" + ii);//输出的不是地址,证明已重写toString方法
 
        // 方式2
        String s = "100";
        // NumberFormatException
        // String s = "abc"; (报错)
        Integer iii = new Integer(s);
        System.out.println("iii:" + iii);
    }
}
 
21.int类型和String类型的相互转换
int -- String
 *         String.valueOf(number)
 * 
 * String -- int
 *         Integer.parseInt(s)
public class IntegerDemo {
    public static void main(String[] args) {
        // int -- String
        int number = 100;
        // 方式1
        String s1 = "" + number;
        System.out.println("s1:" + s1);
        // 方式2
        String s2 = String.valueOf(number);
        System.out.println("s2:" + s2);
        // 方式3
        // int -- Integer -- String
        Integer i = new Integer(number);
        String s3 = i.toString();
        System.out.println("s3:" + s3);
        // 方式4
        // public static String toString(int i)
        String s4 = Integer.toString(number);
        System.out.println("s4:" + s4);
        System.out.println("-----------------");
 
        // String -- int
        String s = "100";
        // 方式1
        // String -- Integer -- int
        Integer ii = new Integer(s);
        // public int intValue()
        int x = ii.intValue();
        System.out.println("x:" + x);
        //方式2
        //public static int parseInt(String s)
        int y = Integer.parseInt(s);
        System.out.println("y:"+y);
    }
}
 
22.常用的基本进制转换
 * public static String toBinaryString(int i)
 * public static String toOctalString(int i)
 * public static String toHexString(int i)
 
 
 * 
 * 十进制到其他进制
 * public static String toString(int i,int radix)
 * 由这个我们也看到了进制的范围:2-36
 * 为什么呢?0,...9,a...z(10+26)
 * 
 * 其他进制到十进制
 * public static int parseInt(String s,int radix)
 
//示例
// 十进制到二进制,八进制,十六进制
        System.out.println(Integer.toBinaryString(100));
        System.out.println(Integer.toOctalString(100));
        System.out.println(Integer.toHexString(100));
        System.out.println("-------------------------");
 
 
//NumberFormatException
        //System.out.println(Integer.parseInt("123", 2));(报错原因:123不是合法的二进制表示)
23.JDK5的新特性自动装箱和拆箱
 
 
// 定义了一个int类型的包装类类型变量i
        // Integer i = new Integer(100);
        Integer ii = 100;
        ii += 200;
        System.out.println("ii:" + ii);
 
        // 通过反编译后的代码
        // Integer ii = Integer.valueOf(100); //自动装箱
        // ii = Integer.valueOf(ii.intValue() + 200); //自动拆箱,再自动装箱
        // System.out.println((new StringBuilder("ii:")).append(ii).toString());
 
 

        Integer iii = null;
        // NullPointerException(注意空指针异常)
        if (iii != null) {
            iii += 1000;
            System.out.println(iii);
        }
24.Integer面试题
 
/*
 * 看程序写结果(since JDK 1.5)
 * 
 * 注意:Integer的数据直接赋值,如果在-128到127之间,会直接从缓冲池里获取数据(不会再通过new来创建)
 */
public class IntegerDemo {
    public static void main(String[] args) {
        Integer i1 = new Integer(127);
        Integer i2 = new Integer(127);
        System.out.println(i1 == i2);
        System.out.println(i1.equals(i2));
        System.out.println("-----------");
 
        Integer i3 = new Integer(128);
        Integer i4 = new Integer(128);
        System.out.println(i3 == i4);
        System.out.println(i3.equals(i4));
        System.out.println("-----------");
 
        Integer i5 = 128;
        Integer i6 = 128;
        System.out.println(i5 == i6);
        System.out.println(i5.equals(i6));
        System.out.println("-----------");
 
        Integer i7 = 127;
        Integer i8 = 127;
        System.out.println(i7 == i8);
        System.out.println(i7.equals(i8));
 
        // 通过查看源码,我们就知道了,针对-128到127之间的数据,做了一个数据缓冲池,如果数据是该范围内的,每次并不创建新的空间
        // Integer ii = Integer.valueOf(127);//反编译查询
    }
}
图解
equals方法被重写过,所以比较的是内容,均为true;
 
 
查源码(跟踪valueOf方法)
 
跟踪low
 
25.Character类
构造方法
、Character 类在对象中包装一个基本类型 char 的值
 * 此外,该类提供了几种方法,以确定字符的类别(小写字母,数字,等等),并将字符从大写转换成小写,反之亦然
 * 
 * 构造方法:
 *         Character(char value)
 
Character ch = new Character('a');
        System.out.println("ch:" + ch); //输出ch:a    toString方法重写
26.Character类的常用方法
public static boolean isUpperCase(char ch):判断给定的字符是否是大写字符
 * public static boolean isLowerCase(char ch):判断给定的字符是否是小写字符
 * public static boolean isDigit(char ch):判断给定的字符是否是数字字符
 * public static char toUpperCase(char ch):把给定的字符转换为大写字符
 * public static char toLowerCase(char ch):把给定的字符转换为小写字符
举例
System.out.println("isUpperCase:" + Character.isUpperCase('A'));
System.out.println("isLowerCase:" + Character.isLowerCase('a'));
System.out.println("isDigit:" + Character.isDigit('0'));
 
 
 
day14
1.
l正则表达式:是指一个用来描述或者匹配一系列符合某个句法规则的字符串的单个字符串。其实就是一种规则。有自己特殊的应用。
l
l举例:校验qq号码.

  1:要求必须是5-15位数字

  2:0不能开头

=================================================================

不用正则表达式的做法

import java.util.Scanner;
 
/*
 * 校验qq号码.
 *         1:要求必须是5-15位数字
 *         2:0不能开头
 * 
 * 分析:
 *         A:键盘录入一个QQ号码
 *         B:写一个功能实现校验
 *         C:调用功能,输出结果。
 */
public class RegexDemo {
    public static void main(String[] args) {
        // 创建键盘录入对象
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入你的QQ号码:");
        String qq = sc.nextLine();
 
        System.out.println("checkQQ:"+checkQQ(qq));
    }
 
    /*
     * 写一个功能实现校验 两个明确: 明确返回值类型:boolean 明确参数列表:String qq
     */
    public static boolean checkQQ(String qq) {
        boolean flag = true;
 
        // 校验长度
        if (qq.length() >= 5 && qq.length() <= 15) {
            // 0不能开头
            if (!qq.startsWith("0")) {
                // 必须是数字
                char[] chs = qq.toCharArray();
                for (int x = 0; x < chs.length; x++) {
                    char ch = chs[x];
                    if (!Character.isDigit(ch)) {
                        flag = false;
                        break;
                    }
                }
            } else {
                flag = false;
            }
        } else {
            flag = false;
        }
 
        return flag;
    }
}
 
用正则表达式改进
下图---String类中的API
 
/*
 * 正则表达式:符合一定规则的字符串。
 */
public class RegexDemo2 {
    public static void main(String[] args) {
        // 创建键盘录入对象
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入你的QQ号码:");
        String qq = sc.nextLine();
 
        System.out.println("checkQQ:" + checkQQ(qq));
    }
 
    public static boolean checkQQ(String qq) {
        // String regex ="[1-9][0-9]{4,14}";
        // //public boolean matches(String regex)告知此字符串是否匹配给定的正则表达式
        // boolean flag = qq.matches(regex);
        // return flag;
 
        //return qq.matches("[1-9][0-9]{4,14}");//简化版,一行代码
 
        return qq.matches("[1-9]\\d{4,14}");
    }
}
 
2.正则表达式的规则 
规则字符在java.util.regexPattern类中
A:字符
    x 字符 x。举例:'a'表示字符a(任意的字符表示它本身)
    \\ 反斜线字符。("\\"表示反斜线\)
    \n 新行(换行)符 ('\u000A') 
    \r 回车符 ('\u000D')
B:字符类(把很多字符都放到一起)
    [abc] a、b  c(简单类)(意为匹配三选一,但不能同时匹配两个,例如ab) 
    [^abc] 任何字符,除了 a、b 或 c(否定) 
    [a-zA-Z] a到 z 或 A到 Z,两头的字母包括在内(范围) (这个写法就意味着包括了所有英文字母)
    [0-9] 0到9的字符都包括
 
例如上面:[1-9][0-9]{4,14}
代表qq号码第一个数字在1~9范围之内(也就是不能为零),第二个数字开始(后面的{4,14}规定了除了第一个数字之外,还包含了4~14之间任意的数字个数,而这些数字的取值范围就在0-9之间)(总的来说就是qq号码一共是5-15个数字,其中第一个数字不能为零,剩余的4-14个数字可以为零)
 
C:预定义字符类(\有转义字符的意思)
    . 任何字符。我的就是.字符本身,怎么表示呢? \.
    \d 数字:[0-9]
例如上面:[1-9][0-9]{4,14}可以改写为[1-9]\\d{4,14}
    \w 单词字符:[a-zA-Z_0-9]
        在正则表达式里面组成单词的东西必须有这些东西组成
D:边界匹配器
    ^ 行的开头 
    $ 行的结尾 
    \b 单词边界
        就是不是单词字符的地方。(单词与单词之间隔开的东西,如下面单词与单词之间的空格,还有?;)
        举例:hello world?haha;xixi
E:Greedy 数量词 
    X? X,一次或一次也没有(0次或者1次)
    X* X,零次或多次(0次或者1次以上)
    X+ X,一次或多次
    X{n} X,恰好 n 次 
    X{n,} X,至少 n 次 
    X{n,m} X,至少 n 次,但是不超过 m 次 
例如上面:[1-9][0-9]{4,14}代表[0-9]至少出现4次但不超过14次([1-9]不给出次数,默认为一次)
3.
 * 判断功能
 *        String类的public boolean matches(String regex)
 *
 * 需求:
 *         判断手机号码是否满足要求?
 * 
 * 分析:
 *         A:键盘录入手机号码
 *         B:定义手机号码的规则
 *             13436975980
 *             13688886868
 *             13866668888
 *             13456789012
 *             13123456789
 *             18912345678
 *             18886867878
 *             18638833883
 *         C:调用功能,判断即可
 *         D:输出结果
 */
public class RegexDemo {
    public static void main(String[] args) {
        //键盘录入手机号码
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入你的手机号码:");
        String phone = sc.nextLine();
 
        //定义手机号码的规则
        String regex = "1[38]\\d{9}";
 
        //调用功能,判断即可
        boolean flag = phone.matches(regex);
 
        //输出结果
        System.out.println("flag:"+flag);
    }
}
4.校验邮箱案例(判断功能)
import java.util.Scanner;
 
/*
 * 校验邮箱
 * 
 * 分析:
 *         A:键盘录入邮箱
 *         B:定义邮箱的规则
 *             1517806580@qq.com
 *             liuyi@163.com
 *             linqingxia@126.com
 *             fengqingyang@sina.com.cn
 *             fqy@itcast.cn
 *         C:调用功能,判断即可
 *         D:输出结果
 */
public class RegexTest {
    public static void main(String[] args) {
        //键盘录入邮箱
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入邮箱:");
        String email = sc.nextLine();
 
        //定义邮箱的规则
        //String regex = "[a-zA-Z_0-9]+@[a-zA-Z_0-9]{2,6}(\\.[a-zA-Z_0-9]{2,3})+";
        String regex = "\\w+@\\w{2,6}(\\.\\w{2,3})+";
 
        //调用功能,判断即可
        boolean flag = email.matches(regex);
 
        //输出结果
        System.out.println("flag:"+flag);
    }
}
5.正则表达式 分割功能
String类的public String[] split(String regex)
    根据给定正则表达式的匹配拆分此字符串。
 
/*举例:
          百合网,世纪佳缘,珍爱网,QQ
        搜索好友
            性别:女
              范围:"18-24"
 
         age>=18 && age<=24
*/
public class RegexDemo {
    public static void main(String[] args) {
        //定义一个年龄搜索范围
        String ages = "18-24";
 
        //定义规则
        String regex = "-";
 
        //调用方法
        String[] strArray = ages.split(regex);
 
//        //遍历
//        for(int x=0; x<strArray.length; x++){
//            System.out.println(strArray[x]);
//        }
 
        //如何得到int类型的呢?
        int startAge = Integer.parseInt(strArray[0]);
        int endAge = Integer.parseInt(strArray[1]);
 
        //键盘录入年龄
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入你的年龄:");
        int age = sc.nextInt();
 
        if(age>=startAge && age<=endAge) {
            System.out.println("你就是我想找的");
        }else {
            System.out.println("不符合我的要求,gun");
        }
    }
}
6.分隔功能练习
 
public class RegexDemo2 {
    public static void main(String[] args) {
        // 定义一个字符串
        String s1 = "aa,bb,cc";
        // 直接分割   split(regex)
        String[] str1Array = s1.split(",");
        for (int x = 0; x < str1Array.length; x++) {
            System.out.println(str1Array[x]);
        }
        System.out.println("---------------------");
 
        String s2 = "aa.bb.cc";
        String[] str2Array = s2.split("\\.");//注意这里不能直接写点号,因为在正则表达式里面点号表示任意字符
                                                              //,应该用\\.
        for (int x = 0; x < str2Array.length; x++) {
            System.out.println(str2Array[x]);
        }
        System.out.println("---------------------");
 
        String s3 = "aa    bb                cc";
        String[] str3Array = s3.split(" +");//这里写的regex的意思是任意多个的空格(+前面的空格代表空格,而+表示
                                                               //空格 有 一次或者一次以上)
        for (int x = 0; x < str3Array.length; x++) {
            System.out.println(str3Array[x]);
        }
        System.out.println("---------------------");
 
        //硬盘上的路径,我们应该用\\替代\
        String s4 = "E:\\JavaSE\\day14\\avi";
        String[] str4Array = s4.split("\\\\");//注意这里是4个杠!!
        for (int x = 0; x < str4Array.length; x++) {
            System.out.println(str4Array[x]);
        }
        System.out.println("---------------------");
    }
}
7.分隔功能案例
我有如下一个字符串:"91 27 46 38 50"
 请写代码实现最终输出结果是:"27 38 46 50 91"
import java.util.Arrays;
 
/*
 * 分析:
 *         A:定义一个字符串
 *         B:把字符串进行分割,得到一个字符串数组
 *         C:把字符串数组变换成int数组
 *         D:对int数组排序
 *         E:把排序后的int数组在组装成一个字符串
 *         F:输出字符串
 */
public class RegexTest {
    public static void main(String[] args) {
        // 定义一个字符串
        String s = "91 27 46 38 50";
 
        // 把字符串进行分割,得到一个字符串数组
        String[] strArray = s.split(" ");
 
        // 把字符串数组变换成int数组
        int[] arr = new int[strArray.length];
 
        for (int x = 0; x < arr.length; x++) {
            arr[x] = Integer.parseInt(strArray[x]);
        }
 
        // 对int数组排序
        Arrays.sort(arr);
 
       // 把排序后的int数组在组装成一个字符串(不能直接调用toString方法,因为数字之间由空格隔开而不是逗号隔开)
        StringBuilder sb = new StringBuilder();
        for (int x = 0; x < arr.length; x++) {
            sb.append(arr[x]).append(" ");
        }
        //转化为字符串
        String result = sb.toString().trim();//这里的toString方法是StringBuilder 转换成String类型的过程,
                                                                //trim()方法旨在去掉字符串最后一个空格
 
        //输出字符串
        System.out.println("result:"+result);
    }
}
8.正则表达式替换功能
     String类的public String replaceAll(String regex,String replacement)
     使用给定的 replacement 替换此字符串所有匹配给定的正则表达式的子字符串。
public class RegexDemo {
    public static void main(String[] args) {
        // 定义一个字符串
        String s = "helloqq12345worldkh622112345678java";
 
        // 我要去除所有的数字,用*给替换掉
        // String regex = "\\d+";
        // String regex = "\\d";
        //String ss = "*";
 
 
        // 直接把数字干掉
        String regex = "\\d+";
        String ss = "";
 
        String result = s.replaceAll(regex, ss);
        System.out.println(result);
    }
}
 
9.Pattern和Matcher的概述
 
10.正则表达式的获取功能
 
 
 
 
import java.util.regex.Matcher;
import java.util.regex.Pattern;
 
/*
 * 获取功能:
 * 获取下面这个字符串中由三个字符组成的单词
 * da jia ting wo shuo,jin tian yao xia yu,bu shang wan zi xi,gao xing bu?
 */
public class RegexDemo2 {
    public static void main(String[] args) {
        // 定义字符串
        String s = "da jia ting wo shuo,jin tian yao xia yu,bu shang wan zi xi,gao xing bu?";
        // 规则
        String regex = "\\b\\w{3}\\b";
 
        // 把规则编译成模式对象
        Pattern p = Pattern.compile(regex);
        // 通过模式对象得到匹配器对象
        Matcher m = p.matcher(s);
        // 调用匹配器对象的功能
        // 通过find方法就是查找有没有满足条件的子串
        // public boolean find()
        // boolean flag = m.find();
        // System.out.println(flag);
        // // 如何得到值呢?
        // // public String group()
        // String ss = m.group();
        // System.out.println(ss);
   
         while (m.find()) {
            System.out.println(m.group());
        }
 
        // 注意:一定要先find(),然后才能group()
        // IllegalStateException: No match found
        // String ss = m.group();
        // System.out.println(ss);
    }
}
 
简化如下
public class RegexDemo2 {
    public static void main(String[] args) {
        // 定义一个字符串
        String s = "da jia ting wo shuo,jin tian yao xia yu,bu shang wan zi xi,gao xing bu?";
 
        // 定义规则
        String regex = "\\b\\w{3}\\b";
 
        Pattern p = Pattern.compile(regex);
        Matcher m = p.matcher(s);
        // boolean b = m.find();
        while (m.find()) {
            System.out.println(m.group());
        }
 
    }
}
 
11.Math类
Math:用于数学运算的类。
  成员变量:
          public static final double PI
         public static final double E
  成员方法:
          public static int abs(int a):绝对值
         public static double ceil(double a):向上取整
         public static double floor(double a):向下取整
        public static int max(int a,int b):最大值 (min自学)
         public static double pow(double a,double b):a的b次幂
         public static double random():随机数 [0.0,1.0)
         public static int round(float a) 四舍五入(参数为double的自学)
         public static double sqrt(double a):平方根
举例:
 
        // public static double ceil(double a):向上取整(与四舍五入无关)
        System.out.println("ceil:" + Math.ceil(12.34));//ceil:13.0
        System.out.println("ceil:" + Math.ceil(12.56));//ceil:13.0
        System.out.println("--------------");
 
        // public static double floor(double a):向下取整(与四舍五入无关)
        System.out.println("floor:" + Math.floor(12.34));//floor:12.0
        System.out.println("floor:" + Math.floor(12.56));//floor:12.0
        System.out.println("--------------");
 
 
最大值应用举例
// public static int max(int a,int b):最大值
        System.out.println("max:" + Math.max(12, 23));
        // 需求:我要获取三个数据中的最大值
        // 方法的嵌套调用
        System.out.println("max:" + Math.max(Math.max(12, 23), 18));
        // 需求:我要获取四个数据中的最大值
        System.out.println("max:"
                + Math.max(Math.max(12, 78), Math.max(34, 56)));
        System.out.println("--------------");
 
随机数举例
// 获取一个1-100之间的随机数
        System.out.println("random:" + ((int) (Math.random() * 100) + 1));//注意这里的优先级!!少了外层的括号 
                                                                                                // random将与前面的字符串拼接形成类似于981的数
        System.out.println("--------------");
 
 
四舍五入举例
System.out.println("round:" + Math.round(12.34f));//round:12
  System.out.println("round:" + Math.round(12.56f));//round:13
round原理如下图:
 
12.一道面试题
需求:请设计一个方法,可以实现获取任意范围内的随机数
 
  分析:
          A:键盘录入两个数据。
              int start;
              int end;
          B:想办法获取在start到end之间的随机数
              我写一个功能实现这个效果,得到一个随机数。(int)
          C:输出这个随机数
 
public class MathDemo {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入开始数:");
        int start = sc.nextInt();
        System.out.println("请输入结束数:");
        int end = sc.nextInt();
 
        for (int x = 0; x < 100; x++) {      //这里的for循环是为了多测试几组数据,非必要。
            // 调用功能
            int num = getRandom(start, end);
            // 输出结果
            System.out.println(num);
        }
    }
 
    /*
     * 写一个功能 两个明确: 返回值类型:int 参数列表:int start,int end
     */
    public static int getRandom(int start, int end) {
        // 回想我们讲过的1-100之间的随机数
        // int number = (int) (Math.random() * 100) + 1;
        // int number = (int) (Math.random() * end) + start;
        // 发现有问题了,怎么办呢?
        int number = (int) (Math.random() * (end - start + 1)) + start;
        return number;
    }
}
13.Random类
Random:产生随机数的类
import java.util.Random;
构造方法:
         public Random():没有给种子,用的是默认种子是当前时间的毫秒值
         public Random(long seed):给出指定的种子
 
        给定种子后,每次得到的随机数是相同的。
 
  成员方法:
          public int nextInt():返回的是int范围内的随机数
         public int nextInt(int n):返回的是[0,n)范围的内随机数
 
举例
public class RandomDemo {
    public static void main(String[] args) {
        // 创建对象
        // Random r = new Random();
        Random r = new Random(1111);
 
        for (int x = 0; x < 10; x++) {
            // int num = r.nextInt();
            int num = r.nextInt(100) + 1;
            System.out.println(num);
        }
    }
}
 
14.System类
 
 
System.gc()

System.gc()可用于垃圾回收。当使用System.gc()回收某个对象所占用的内存之前,通过要求程序调用适当的方法来清理资源。在没有明确指定资源清理的情况下,Java提高了默认机制来清理该对象的资源,就是调用Object类的finalize()方法。finalize()方法的作用是释放一个对象占用的内存空间时,会被JVM调用。而子类重写该方法,就可以清理对象占用的资源,该方法有没有链式调用,所以必须手动实现。

 

 

 

从程序的运行结果可以发现,执行System.gc()前,系统会自动调用finalize()方法清除对象占有的资源,通过super.finalize()方式可以实现从下到上的finalize()方法的调用,即先释放自己的资源,再去释放父类的资源。

但是,不要在程序中频繁的调用垃圾回收,因为每一次执行垃圾回收,jvm都会强制启动垃圾回收器运行,这会耗费更多的系统资源,会与正常的Java程序运行争抢资源,只有在执行大量的对象的释放,才调用垃圾回收最好

15.System.exit(0)

public static void exit(int status):终止当前正在运行的 Java 虚拟机。参数用作状态码;根据惯例,非 0 的状态码表示异常终止。(0表示正常)
所以,建议用exit(0);
16.System类 currentTimeMillis()
 
System.out.println(System.currentTimeMillis());
 
        单独得到这样的实际目前对我们来说意义不大
         那么,它到底有什么作用呢?
         要求:请大家给我统计这段程序的运行时间
        long start = System.currentTimeMillis();
        for (int x = 0; x < 100000; x++) {
            System.out.println("hello" + x);
        }
        long end = System.currentTimeMillis();
        System.out.println("共耗时:" + (end - start) + "毫秒");
    }
 
 
17.system类 arraycopy(注意,arraycopy并不符合命名规则(since JDK1.0),但是不改了)
public static void arraycopy(Object src,int srcPos,Object dest,int destPos,int length)
   从指定源数组中复制一个数组,复制从指定的位置开始,到目标数组的指定位置结束。
举例
 
        int[] arr = { 11, 22, 33, 44, 55 };
        int[] arr2 = { 6, 7, 8, 9, 10 };
 
        System.arraycopy(arr, 1, arr2, 2, 2);
 
        System.out.println(Arrays.toString(arr));//[11, 22, 33, 44, 55]
 
        System.out.println(Arrays.toString(arr2));//[6, 7, 22, 33, 10]
 
注意Arrays.toString(……)方法
 
18.BigInteger类---可以让超过Integer范围内的数据进行运算(即超过2147483647)
java.math.BigInteger
public BigInteger add(BigInteger val):加
 public BigInteger subtract(BigInteger val):减
  public BigInteger multiply(BigInteger val):乘
 public BigInteger divide(BigInteger val):除
  public BigInteger[] divideAndRemainder(BigInteger val):返回商和余数的数组
 
 
BigInteger bi1 = new BigInteger("100");
 BigInteger bi2 = new BigInteger("50");
 
BigInteger[] bis = bi1.divideAndRemainder(bi2);
 System.out.println(":" + bis[0]);//2
 System.out.println("余数:" + bis[1]);//0
 
19.  BigDecimal
由于在运算的时候,float类型和double很容易丢失精度,演示案例。所以,为了能精确的表示、计算浮点数,Java提供了BigDecimal
 
public BigInteger add(BigInteger val):加
 * public BigInteger subtract(BigInteger val):减
 * public BigInteger multiply(BigInteger val):乘
 * public BigInteger divide(BigInteger val):除
 * public BigInteger[] divideAndRemainder(BigInteger val):返回商和余数的数组
 

divisor - 此 BigDecimal 要除以的值。scale - 要返回的 BigDecimal 商的标度。(也就是保留多少位小数)roundingMode - 要应用的舍入模式。(一般用ROUND_HALF_UP----即四舍五入)
 
 
20.Date类
 
Date:表示特定的瞬间,精确到毫秒。
Date的构造方法
        Date():根据当前的默认毫秒值创建日期对象
       Date(long date):根据给定的毫秒值创建日期对象
 
获取当前时间
long time = System.currentTimeMillis();
Date d2 = new Date(time);
System.out.println("d2:" + d2);
 
21.Date类的一些方法
public long getTime():获取时间,以毫秒为单位
 public void setTime(long time):设置时间
 
掌握两个方法(转换)
从Date得到一个毫秒值
          getTime()
  把一个毫秒值转换为Date
         构造方法
         setTime(long time)
 
/ 创建对象
        Date d = new Date();
 
        // 获取时间
        long time = d.getTime();
        System.out.println(time);
        // System.out.println(System.currentTimeMillis());
 
        System.out.println("d:" + d);
        // 设置时间
        d.setTime(1000);//1000代表1000毫秒
        System.out.println("d:" + d);
 
22.DateFormat
String和Date的相互转换理解
 
Date     --     String(格式化)
          public final String format(Date date)(这个是具体子类SimpleDateFormat的父类DateForamt中的一个方法)
  
  String -- Date(解析)
         public Date parse(String source)
 
  DateForamt:可以进行日期和字符串的格式化和解析,但是由于是抽象类,所以使用具体子类SimpleDateFormat。
 
// Date -- String
        // 创建日期对象
        Date d = new Date();
        // 创建格式化对象
        // SimpleDateFormat sdf = new SimpleDateFormat();
        // 给定模式
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
        // public final String format(Date date)
        String s = sdf.format(d);//子类调用父类的方法
        System.out.println(s);
基础输出
 
总结:
Date     --     String(格式化)
         public final String format(Date date)
  
  String -- Date(解析)
          public Date parse(String source)
  
  DateForamt:可以进行日期和字符串的格式化和解析,但是由于是抽象类,所以使用具体子类SimpleDateFormat。
  
  SimpleDateFormat的构造方法:
         SimpleDateFormat():默认模式
         SimpleDateFormat(String pattern):给定的模式
              这个模式字符串该如何写呢?
             通过查看API,我们就找到了对应的模式
             
 年 y
              月 M    
              日 d
              时 H
              分 m
              秒 s
           2014年12月12日 12:12:12
 
具体方法
-1-.日期转字符串
Date d = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");//给定模式
String s = sdf.format(d);//format意为格式化
System.out.println(s);
输出如下
 
-2-字符串转日期
String str = "2008-08-08 12:12:12";
//在把一个字符串解析为日期的时候,请注意格式必须和给定的字符串格式匹配
SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date dd = sdf2.parse(str);//parse意为解析
 
 

23.Date类一个综合案例----你来到这个世界多少天
你来到这个世界多少天
分析:
          A:键盘录入你的出生的年月日
          B:把该字符串转换为一个日期
          C:通过该日期得到一个毫秒值
          D:获取当前时间的毫秒值
          E:用D-C得到一个毫秒值
          F:把E的毫秒值转换为年
                                 /1000/60/60/24
本人写法
输出测试结果
 
24.Calendar类(抽象类)以及getInstance()和get()方法
Calendar:它为特定瞬间与一组诸如 YEAR、MONTH、DAY_OF_MONTH、HOUR 等 日历字段之间的转换提供了一些方法,并为操作日历字段(例如获得下星期的日期)提供了一些方法。
  
  public int get(int field):返回给定日历字段的值。日历类中的每个日历字段都是静态的成员变量,并且是int类型
下图解析 Calendar rightNow = Calendar.getInstance(); (运用了多态)(具体可查API)
 
// 其日历字段已由当前日期和时间初始化:
        Calendar rightNow = Calendar.getInstance(); // 子类对象
 
        // 获取年
        int year = rightNow.get(Calendar.YEAR);
        // 获取月
        int month = rightNow.get(Calendar.MONTH);
        // 获取日
        int date = rightNow.get(Calendar.DATE);
 
        System.out.println(year + "年" + (month + 1) + "月" + date + "日");
 
25.Calendar类另外两个方法
public void add(int field,int amount):根据给定的日历字段和对应的时间,来对当前的日历进行操作。(amount可以是负的)
 public final void set(int year,int month,int date):设置当前日历的年月日
 
承接上一节的获取时间
三年前的今天
 
5年10天前
 
注意set 方法中的month小问题(month从0开始)
 
附:Calendar也有获得毫秒值的方法(具体看API)
 
26.一个小案例------获取任意一年的二月有多少天
 
import java.util.Calendar;
import java.util.Scanner;
 
/*
 * 获取任意一年的二月有多少天(注意month从0开始)
 * 
 * 分析:
 *         A:键盘录入任意的年份
 *         B:设置日历对象的年月日
 *             年就是A输入的数据
 *             月是2
 *             日是1
 *         C:把时间往前推一天,就是2月的最后一天
 *         D:获取这一天输出即可
 */
public class CalendarTest {
    public static void main(String[] args) {
        // 键盘录入任意的年份
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入年份:");
        int year = sc.nextInt();
 
        // 设置日历对象的年月日
        Calendar c = Calendar.getInstance();
        c.set(year, 2, 1); // 其实是这一年的3月1日
        // 把时间往前推一天,就是2月的最后一天
        c.add(Calendar.DATE, -1);
 
        // 获取这一天输出即可
        System.out.println(c.get(Calendar.DATE));
    }
}
 
day14补充
Calendar
    (1)日历类,封装了所有的日历字段值,通过统一的方法根据传入不同的日历字段可以获取值。
    (2)如何得到一个日历对象呢?
        Calendar rightNow = Calendar.getInstance();
        本质返回的是子类对象
 
day15
1.对象数组的内存图解
 
2.集合概述
集合的由来:
          我们学习的是面向对象语言,而面向对象语言对事物的描述是通过对象体现的,为了方便对多个对象进行操作,我们就必须把这多个对象进行存储。
          而要想存储多个对象,就不能是一个基本的变量,而应该是一个容器类型的变量,在我们目前所学过的知识里面,有哪些是容器类型的呢?
          数组和StringBuffer。但是呢?StringBuffer的结果是一个字符串,不一定满足我们的要求,所以我们只能选择数组,这就是对象数组。
          而对象数组又不能适应变化的需求,因为数组的长度是固定的,这个时候,为了适应变化的需求,Java就提供了集合类供我们使用。
 
3.数组和集合的区别?
          A:长度区别
              数组的长度固定
              集合长度可变
          B:内容不同
              数组存储的是同一种类型的元素
              而集合可以存储不同类型的元素
          C:元素的数据类型问题    
              数组可以存储基本数据类型,也可以存储引用数据类型
              集合只能存储引用类型
 
3.集合的继承体系图解
4.Collection
Collection:是集合的顶层接口,它的子体系有重复的,有唯一的,有有序的,有无序的。
  
  Collection的功能概述
  1:添加功能
         boolean add(Object obj):添加一个元素
          boolean addAll(Collection c):添加一个集合的元素
  2:删除功能
          void clear():移除所有元素
          boolean remove(Object o):移除一个元素
          boolean removeAll(Collection c):移除一个集合的元素(是一个还是所有)
  3:判断功能
          boolean contains(Object o):判断集合中是否包含指定的元素
          boolean containsAll(Collection c):判断集合中是否包含指定的集合元素(是一个还是所有)
          boolean isEmpty():判断集合是否为空
  4:获取功能
          Iterator<E> iterator()(重点)
  5:长度功能
          int size():元素的个数
         
 面试题:数组有没有length()方法呢?字符串有没有length()方法呢?集合有没有length()方法呢?
  6:交集功能
          boolean retainAll(Collection c):两个集合都有的元素?思考元素去哪了,返回的boolean又是什么意思呢?
 7:把集合转换为数组
          Object[] toArray()
5.重点注意几个All方法
boolean addAll(Collection c):添加一个集合的元素
 boolean removeAll(Collection c):移除一个集合的元素(是一个还是所有)
 boolean containsAll(Collection c):判断集合中是否包含指定的集合元素(只有包含所有的元素,才叫包含)
  boolean retainAll(Collection c):两个集合都有的元素?思考元素去哪了,返回的boolean又是什么意思呢?
 
addAll示例
removeAll示例(只要有一个元素被移除了,就返回true)
注意
boolean retainAll(Collection c):两个集合都有的元素?思考元素去哪了,返回的boolean又是什么意思呢?
        //假设有两个集合A,B。
        //A对B做交集,最终的结果保存在A中,B不变。
        //返回值表示的是A是否发生过改变。
 
 
 
 
 
返回值表示的是A(原集合)是否发生过改变。
 
6.集合的遍历
集合的遍历,其实就是依次获取集合中的每一个元素。
Object[] toArray():把集合转成数组,可以实现集合的遍历
 
// 创建集合对象
        Collection c = new ArrayList();
 
        // 添加元素
        c.add("hello"); // 这个语句隐含有Object obj = "hello"; 向上转型
        c.add("world");
        c.add("java");
 
        // 遍历
        // Object[] toArray():把集合转成数组,可以实现集合的遍历
        Object[] objs = c.toArray();
        for (int x = 0; x < objs.length; x++) {
            // System.out.println(objs[x]);
            // 我知道元素是字符串,我在获取到元素的的同时,还想知道元素的长度
            // System.out.println(objs[x] + "---" + objs[x].length());
            // 上面的实现不了,原因是Object中没有length()方法
            // 我们要想使用字符串的方法,就必须把元素还原成字符串
            // 向下转型
            String s = (String) objs[x];
            System.out.println(s + "---" + s.length());
7.集合的遍历案例(最原始的遍历方式,以后不常用,用迭代器取代)
练习:用集合存储5个学生对象,并把学生对象进行遍历。
 * 
 * 分析:
 * A:创建学生类
 * B:创建集合对象
 * C:创建学生对象
 * D:把学生添加到集合
 * E:把集合转成数组
 * F:遍历数组
 
 
public class StudentDemo {
    public static void main(String[] args) {
        // 创建集合对象
        Collection c = new ArrayList();
 
        // 创建学生对象
        Student s1 = new Student("林青霞", 27);
        Student s2 = new Student("风清扬", 30);
        Student s3 = new Student("令狐冲", 33);
        Student s4 = new Student("武鑫", 25);
        Student s5 = new Student("刘晓曲", 22);
 
        // 把学生添加到集合
        c.add(s1);
        c.add(s2);
        c.add(s3);
        c.add(s4);
        c.add(s5);
 
        // 把集合转成数组
        Object[] objs = c.toArray();
        // 遍历数组
        for (int x = 0; x < objs.length; x++) {
            // System.out.println(objs[x]);
 
            Student s = (Student) objs[x];
            System.out.println(s.getName() + "---" + s.getAge());
        }
    }
}
所需的同一个包下的Student类如下
 
 
8.Iterator迭代器
Iterator iterator():迭代器,集合的专用遍历方式
         
 Object next():获取元素,并移动到下一个位置。
         boolean hasNext():如果仍有元素可以迭代,则返回 true。
典型写法
Collection c = new ArrayList();
c.add("hello");
c.add("world");
c.add("java");
 
Iterator it = c.iterator(); // 实际返回的肯定是子类对象,这里是多态
 
while (it.hasNext()) {
            // System.out.println(it.next());//这个其实也可以
            String s = (String) it.next();//建议向下转型
            System.out.println(s);
        }
 
9.注意事项
 
10.迭代器使用图解和原理解析
 
 
 
迭代器的源码 Iterator  Iterable  Collection都是接口
 
public interface Iterator {
    boolean hasNext();
    Object next(); 
}
 
public interface Iterable {
    Iterator iterator();//这个方法到这里还没有实现
}
 
public interface Collection extends Iterable {
    Iterator iterator();//这个方法到这里还没有实现
}
 
public interface List extends Collection {
    Iterator iterator();//这个方法到这里还没有实现
}
 
public class ArrayList implements List {
    public Iterator iterator() {
        return new Itr();//这个方法到这里开始实现
    }
 
    private class Itr implements Iterator {
        public boolean hasNext() {}
        public Object next(){} //直到这里上面的接口方法才算真正实现了
    }
}
 
 
Collection c = new ArrayList();
c.add("hello");
c.add("world");
c.add("java");
Iterator it = c.iterator();     //new Itr();
while(it.hasNext()) {
    String s = (String)it.next();
    System.out.println(s);
}
 
11.List接口概述
有序的
 collection(也称为序列)。此接口的用户可以对列表中每个元素的插入位置进行精确地控制。用户可以根据元素的整数索引(在列表中的位置)访问元素,并搜索列表中的元素。
 set 不同,列表通常允许重复的元素。
 
12.List集合的特有功能:
  A:添加功能
          void add(int index,Object element):在指定位置添加元素
  B:获取功能
          Object get(int index):获取指定位置的元素
  C:列表迭代器
          ListIterator listIterator():List集合特有的迭代器
  D:删除功能
         Object remove(int index):根据索引删除元素,返回被删除的元素
  E:修改功能
          Object set(int index,Object element):根据索引修改元素,返回被修饰的元素
 
13.ListIterator特有功能
 
public class ListDemo4 {
    public static void main(String[] args) {
        List list = new ArrayList();
 
        list.add("hello");
        list.add("world");
        list.add("java");
 
        ListIterator lit = list.listIterator();
        while (lit.hasNext()) {
            String s = (String) lit.next();
            System.out.println(s);
        }
 
        System.out.println("----");
 
        while (lit.hasPrevious()) {
            String s = (String) lit.previous();
            System.out.println(s);
        }
 
    }
}
 
14.一个需要注意的问题
问题
       我有一个集合,如下,请问,我想判断里面有没有"world"这个元素,如果有,我就添加一个"javaee"元素,请写代码实现。
 
按常理做法结果如下
 
运行有异常
 
ConcurrentModificationException:当方法检测到对象的并发修改,但不允许这种修改时,抛出此异常。
 
产生的原因:
          迭代器是依赖于集合而存在的,在判断成功后,集合的中新添加了元素,而迭代器却不知道,所以就报错了,这个错叫并发修改异常。
          其实这个问题描述的是:迭代器遍历元素的时候,通过集合是不能修改元素的
  如何解决呢?
          A:迭代器迭代元素,迭代器修改元素
             元素是跟在刚才迭代的元素后面的。
          B:集合遍历元素,集合修改元素(普通for)
              元素在最后添加的。

附:接口 ListIterator<E>有如下几个方法(迭代器修改元素)

 

方法1如图

注意javaee被添加的位置
元素是跟在刚才迭代的元素后面的
 
方法2如图
 
注意javaee被添加的位置
元素在最后添加的
 
15.数据结构
数据结构:数据的组织形式
面试题:常见的数据结构的优缺点
(数据结构+算法)
 
16.List的子类特点
List:(面试题List的子类特点)
    ArrayList:
        底层数据结构是数组,查询快,增删慢。
        线程不安全,效率高。
    Vector:
        底层数据结构是数组,查询快,增删慢。
        线程安全,效率低。
    LinkedList:
        底层数据结构是链表,查询慢,增删快。
        线程不安全,效率高。
 
    List有三个儿子,我们到底使用谁呢?
        看需求(情况)。
 
    要安全吗?
        要:Vector(即使要安全,也不用这个,后面有替代的)
        不要:ArrayList或者LinkedList
            查询多:ArrayList
            增删多:LinkedList
 
day15补充
集合的继承体系结构?
        由于需求不同,Java就提供了不同的集合类。这多个集合类的数据结构不同,但是它们都是要提供存储和遍历功能的,
        我们把它们的共性不断的向上提取,最终就形成了集合的继承体系结构图。
 
        Collection
            |--List
                |--ArrayList
                |--Vector
                |--LinkedList
            |--Set
                |--HashSet
                |--TreeSet
 
day16
1.ArrayList存储自定义对象并遍历
public static void main(String[] args) {
        // 创建集合对象
        ArrayList array = new ArrayList();
 
        // 创建学生对象
        Student s1 = new Student("武松", 30);
        Student s2 = new Student("鲁智深", 40);
        Student s3 = new Student("林冲", 36);
        Student s4 = new Student("杨志", 38);
 
        // 添加元素
        array.add(s1);
        array.add(s2);
        array.add(s3);
        array.add(s4);
 
        // 遍历
        Iterator it = array.iterator();
        while (it.hasNext()) {
            Student s = (Student) it.next();
            System.out.println(s.getName() + "---" + s.getAge());
        }
 
        System.out.println("----------------");
 
        for (int x = 0; x < array.size(); x++) {
          
            Student s = (Student) array.get(x);
            System.out.println(s.getName() + "---" + s.getAge());
        }
    }
 
2.Vector
Vector的特有功能:
 * 1:添加功能
 *         public void addElement(Object obj)        --    被后来的add()替代
 * 2:获取功能
 *         public Object elementAt(int index)        --  被后来的get()替代
 *         public Enumeration elements()            --   被后来的Iterator iterator()替代
 *                 boolean hasMoreElements()                被后来的hasNext()替代
 *                 Object nextElement()                   被后来的next()替代
 * 
 * 附:JDK升级的原因:
 *         A:安全
 *         B:效率
 *         C:简化书写
 
public static void main(String[] args) {
        // 创建集合对象
        Vector v = new Vector();
 
        // 添加功能
        v.addElement("hello");
        v.addElement("world");
        v.addElement("java");
 
        // 遍历
        for (int x = 0; x < v.size(); x++) {
            String s = (String) v.elementAt(x);
            System.out.println(s);
        }
 
        System.out.println("------------------");
 
        Enumeration en = v.elements(); // 返回的是实现类的对象
        while (en.hasMoreElements()) {
            String s = (String) en.nextElement();
            System.out.println(s);
        }
    }
3.LinkedList的特有功能:
 *         A:添加功能
 *             public void addFirst(Object e)
 *             public void addLast(Object e)
 *         B:获取功能
 *             public Object getFirst()
 *             public Obejct getLast()
 *         C:删除功能
 *             public Object removeFirst()
 *             public Object removeLast()

 

 

4.一个案例
ArrayList去除集合中字符串的重复值(字符串的内容相同)
思路
 
分析:
 *         A:创建集合对象
 *         B:添加多个字符串元素(包含内容相同的)
 *         C:创建新集合
 *         D:遍历旧集合,获取得到每一个元素
 *         E:拿这个元素到新集合去找,看有没有
 *             有:不搭理它
 *             没有:就添加到新集合
 *         F:遍历新集合
 
public static void main(String[] args) {
        // 创建集合对象
        ArrayList array = new ArrayList();
 
        // 添加多个字符串元素(包含内容相同的)
        array.add("hello");
        array.add("world");
        array.add("java");
        array.add("world");
        array.add("java");
        array.add("world");
        array.add("world");
        array.add("world");
        array.add("world");
        array.add("java");
        array.add("world");
 
        // 创建新集合
        ArrayList newArray = new ArrayList();
 
        // 遍历旧集合,获取得到每一个元素
        Iterator it = array.iterator();
        while (it.hasNext()) {
            String s = (String) it.next();
 
            // 拿这个元素到新集合去找,看有没有
            if (!newArray.contains(s)) {
                newArray.add(s);
            }
        }
 
        // 遍历新集合
        for (int x = 0; x < newArray.size(); x++) {
            String s = (String) newArray.get(x);
            System.out.println(s);
        }
    }
 
这个案例,注意contains(s)的使用,很容易忽(wang)略(ji)这个功能!!。
5.上一个案例的另外一种思路(有点复杂,理解一下就行,常用上一中方法)
需求:ArrayList去除集合中字符串的重复值(字符串的内容相同)
 要求:不能创建新的集合,就在以前的集合上做。
public static void main(String[] args) {
        // 创建集合对象
        ArrayList array = new ArrayList();
 
        // 添加多个字符串元素(包含内容相同的)
        array.add("hello");
        array.add("world");
        array.add("java");
        array.add("world");
        array.add("java");
        array.add("world");
        array.add("world");
        array.add("world");
        array.add("world");
        array.add("java");
        array.add("world");
 
        // 由选择排序思想引入,我们就可以通过这种思想做这个题目
        // 拿0索引的依次和后面的比较,有就把后的干掉
        // 同理,拿1索引...
        for (int x = 0; x < array.size() - 1; x++) {
            for (int y = x + 1; y < array.size(); y++) {
                if (array.get(x).equals(array.get(y))) {
                    array.remove(y);
                    y--;
                }
            }
        }
 
        // 遍历集合
        Iterator it = array.iterator();
        while (it.hasNext()) {
            String s = (String) it.next();
            System.out.println(s);
        }
    }
 
下面解析一下y--的来源,为什么要有y--,
首先,没有y--,程序结果不对
 
接着,通过设置断点debug发现
 
最后,通过添加y--解决
 
6.另一个案例
需求:去除集合中自定义对象的重复值(对象的成员变量值都相同)
自定义对象可以为学生类
 
我们按照和字符串一样的操作,发现出问题了。
 
public static void main(String[] args) {
        // 创建集合对象
        ArrayList array = new ArrayList();
 
        // 创建学生对象
        Student s1 = new Student("林青霞", 27);
        Student s2 = new Student("林志玲", 40);
        Student s3 = new Student("凤姐", 35);
        Student s4 = new Student("芙蓉姐姐", 18);
        Student s5 = new Student("翠花", 16);
        Student s6 = new Student("林青霞", 27);
        Student s7 = new Student("林青霞", 18);
 
        // 添加元素
        array.add(s1);
        array.add(s2);
        array.add(s3);
        array.add(s4);
        array.add(s5);
        array.add(s6);
        array.add(s7);
 
        // 创建新集合
        ArrayList newArray = new ArrayList();
 
        // 遍历旧集合,获取得到每一个元素
        Iterator it = array.iterator();
        while (it.hasNext()) {
            Student s = (Student) it.next();
 
            // 拿这个元素到新集合去找,看有没有
            if (!newArray.contains(s)) {
                newArray.add(s);
            }
        }
 
        // 遍历新集合
        for (int x = 0; x < newArray.size(); x++) {
            Student s = (Student) newArray.get(x);
            System.out.println(s.getName() + "---" + s.getAge());
        }
    }

 

 

 

为什么呢?
       我们必须思考哪里会出问题?
          通过简单的分析,我们知道问题出现在了判断上。
          而这个判断功能是集合自己提供的,所以我们如果想很清楚的知道它是如何判断的,就应该去看源码。
------有问题,查源码

 

 

 

 

通过查源码发现 
contains()方法的底层依赖的是equals()方法。
  而我们的学生类中没有equals()方法,这个时候,默认使用的是它父亲Object的equals()方法
  Object()的equals()默认比较的是地址值,所以,它们进去了。因为new的东西,地址值都不同。
  按照我们自己的需求,比较成员变量的值,重写equals()即可。(在Student类中重写)
  运用代码自动生成即可。
 
7.请用LinkedList模拟栈数据结构的集合,并测试
 
题目的意思是:
       你自己的定义一个集合类,在这个集合类内部可以使用LinkedList模拟。
MyStack类
MySatckTest
 
8.泛型的引入,概述
有疑问,反编译(xJad)
 
编译不出问题,但是运行就报错了
8.泛型概述和基本使用
回想一下,我们的数组
          String[] strArray = new String[3];
          strArray[0] = "hello";
          strArray[1] = "world";
          strArray[2] = 10;
  集合也模仿着数组的这种做法,在创建对象的时候明确元素的数据类型。这样就不会在有问题了。
  而这种技术被称为:泛型。
  
  泛型:是一种把类型明确的工作推迟到创建对象或者调用方法的时候才去明确的特殊的类型。参数化类型,把类型当作参数一样的传递。
  格式:
          <数据类型>
          此处的数据类型只能是引用类型。
  好处:
          A:把运行时期的问题提前到了编译期间
          B:避免了强制类型转换
          C:优化了程序设计,解决了黄色警告线
 
public static void main(String[] args) {
        // 创建
        ArrayList<String> array = new ArrayList<String>();
 
        // 添加元素
        array.add("hello");
        array.add("world");
        array.add("java");
 
        // 遍历
        Iterator<String> it = array.iterator();
        while (it.hasNext()) {
            // ClassCastException
            // String s = (String) it.next();
            String s = it.next();
            System.out.println(s);
        }
    }
 
2.泛型在哪些地方使用呢?
看API,如果类,接口,抽象类后面跟的有<E>就说要使用泛型。一般来说就是在集合中使用
 
以下用ArrayList存储字符串元素,并遍历。用泛型改进代码
public static void main(String[] args) {
        ArrayList<String> array = new ArrayList<String>();
 
        array.add("hello");
        array.add("world");
        array.add("java");
 
        Iterator<String> it = array.iterator();
        while (it.hasNext()) {
            String s = it.next();
            System.out.println(s);
        }
        System.out.println("-----------------");
 
        for (int x = 0; x < array.size(); x++) {
            String s = array.get(x);
            System.out.println(s);
        }
    }
 
3.JDK7的新特性--------泛型推断
 创建集合对象
  ArrayList<Student> array = new ArrayList<Student>();//一般情况下
   JDK7的新特性:泛型推断
         ArrayList<Student> array = new ArrayList<>();
        但是不建议这样使用。
        ArrayList<Student> array = new ArrayList<Student>();//还是这样写
 
4.泛型类:把泛型定义在类上
举例
=============================================
ObjectTool.java
 
public class ObjectTool<T> {
    private T obj;
 
    public getObj() {
        return obj;
    }
 
    public void setObj(T obj) {
        this.obj = obj;
    }
}
====================================================
ObjectToolDemo.java
 
 
public class ObjectToolDemo {
    public static void main(String[] args) {
        ObjectTool<String> ot = new ObjectTool<String>();
        // ot.setObj(new Integer(27)); //这个时候编译期间就过不去
        ot.setObj(new String("林青霞"));
        String s = ot.getObj();
        System.out.println("姓名是:" + s);
 
        ObjectTool<Integer> ot2 = new ObjectTool<Integer>();
        // ot2.setObj(new String("风清扬"));//这个时候编译期间就过不去
        ot2.setObj(new Integer(27));
        Integer i = ot2.getObj();
        System.out.println("年龄是:" + i);
    }
}
5. 泛型方法:把泛型定义在方法上(这个时候与泛型类无关!)
原始做法
============================
ObjectTool.java
public class ObjectTool<T> {
 
    public void show(T t) {
        System.out.println(t);
    }
 }
============================
ObjectToolDemo.java
 
 ObjectTool<String> ot = new ObjectTool<String>();
        ot.show("hello");
       
        ObjectTool<Integer> ot2 = new ObjectTool<Integer>();
        ot2.show(100);
        
        ObjectTool<Boolean> ot3 = new ObjectTool<Boolean>();
       ot3.show(true);
 
        // 如果还听得懂,那就说明泛型类是没有问题的
        // 但是呢,谁说了我的方法一定要和类的类型的一致呢?
        // 我要是类上没有泛型的话,方法还能不能接收任意类型的参数了呢?
 
 
 
改进(不定义泛型类,但定义了一个普通类的背后定义一个泛型方法)
ObjectTool.java
public class ObjectTool {
    public <T> void show(T t) {
        System.out.println(t);
    }
}
 
// 定义泛型方法后 ObjectToolDemo.java
 
        ObjectTool ot = new ObjectTool();
        ot.show("hello");
        ot.show(100);
        ot.show(true);
 
6.泛型接口:把泛型定义在接口上
================================================
Inter.java(定义一个接口,而且是泛型接口)
public interface Inter<T> {
    public abstract void show(T t);
}
================================================
InterImpl.java(用一个类去实现上面的泛型接口)
//实现类在实现接口的时候
//第一种情况:已经知道该是什么类型的了(用得比较少)
 
//public class InterImpl implements Inter<String> {
//
//    @Override
//    public void show(String t) {
//        System.out.println(t);
//    }
// }
 
//第二种情况:还不知道是什么类型的(这种情况最常见,推荐使用,说白了,就是用泛型类实现泛型接口)
public class InterImpl<T> implements Inter<T> {
 
    @Override
    public void show(T t) {
        System.out.println(t);
    }
}
=================================
InterDemo.java(测试类)
public static void main(String[] args) {
        // 第一种情况的测试
        // Inter<String> i = new InterImpl();//只能是String,否则会报错
        // i.show("hello");
 
        // // 第二种情况的测试
        Inter<String> i = new InterImpl<String>();
        i.show("hello");
 
        Inter<Integer> ii = new InterImpl<Integer>();
        ii.show(100);
    }
7.泛型高级之通配符
泛型高级(通配符)
 ?:任意类型,如果没有明确,那么就是Object以及任意的Java类了
 ? extends E:向下限定,E及其子类
 ? super E:向上限定,E及其父类
 
背景
class Animal {
}
 
class Dog extends Animal {
}
 
class Cat extends Animal {
}
 
泛型如果明确的写的时候,前后必须一致

 

 

?表示任意的类型都是可以的

? extends E:向下限定,E及其子类

? super E:向上限定,E极其父类

(留意以上截图哪些行报错了)

 

8.JDK5的新特性----增强for
JDK5的新特性:自动拆装箱,泛型,增强for,静态导入,可变参数,枚举
  
  增强for:是for循环的一种。
  
  格式:
          for(元素数据类型 变量 : 数组或者Collection集合) {
             使用变量即可,该变量就是元素
        }
  
  好处:简化了数组和集合的遍历。
 
弊端: 增强for的目标不能为null。
 *如何解决呢?对增强for的目标先进行不为null的判断然后再使用
==========================================
public static void main(String[] args) {
        // 定义一个int数组
        int[] arr = { 1, 2, 3, 4, 5 };
        for (int x = 0; x < arr.length; x++) {
            System.out.println(arr[x]);
        }
        System.out.println("---------------");
        // 增强for
        for (int x : arr) {
            System.out.println(x);
        }
        System.out.println("---------------");
        // 定义一个字符串数组
        String[] strArray = { "林青霞", "风清扬", "东方不败", "刘意" };
        // 增强for
        for (String s : strArray) {
            System.out.println(s);
        }
        System.out.println("---------------");
        // 定义一个集合(重点留意这个遍历的简化)
        ArrayList<String> array = new ArrayList<String>();
        array.add("hello");
        array.add("world");
        array.add("java");
        // 增强for
        for (String s : array) {
            System.out.println(s);
        }
        System.out.println("---------------");
    }
==============================================================
弊端: 增强for的目标不能为null。如下面所示
  List<String> list = null;
        // NullPointerException
        // 这个s是我们从list里面获取出来的,在获取前,它肯定还要做一个判断
        // 说白了,这就是迭代器的功能
    //又要获取又要判断,所以抛出异常

 

 

//改进
        if (list != null) { //改进后,加一个判断
            for (String s : list) {
                System.out.println(s);
            }
        }
还有一个值得注意的问题

增强for其实就是(用来替代)迭代器
迭代器遍历集合,集合修改集合会产生并发修改异常。换句话说,增强for就是替代了迭代器(的作用)
详见以下这个例子
 // 增强for其实是用来替代迭代器的
        //ConcurrentModificationException
        // for (String s : array) {
        // if ("world".equals(s)) {
        // array.add("javaee");
        // }
        // }
        // System.out.println("array:" + array);

 

 
9.JDK5的新特性-----静态导入(意义不大,能看懂即可)
 
*静态导入的注意事项:
         A:方法必须是静态的
       B:如果有多个同名的静态方法,容易不知道使用谁?这个时候要使用,必须加前缀。由此可见,意义不大,所以一般不用,但是要能看懂。
 
10.使用Eclipse快速制作方法
 
 
或者选中a + b来做方法也可以
 
11.JDK5的新特性-----可变参数
可变参数:定义方法的时候不知道该定义多少个参数
  格式:
          修饰符 返回值类型 方法名(数据类型…  变量名){
 
          }
  
          注意:
              这里的变量其实是一个数组
              如果一个方法有可变参数,并且有多个参数,那么,可变参数肯定是最后一个(也就是说,可以是
                method(int a, int...b),但不可以是method(int...b,int a) 。)
 
public static void main(String[] args) {
        // 2个数据求和
        int a = 10;
        int b = 20;
        int result = sum(a, b);
        System.out.println("result:" + result);
 
        // 3个数据的求和
        int c = 30;
        result = sum(a, b, c);
        System.out.println("result:" + result);
 
        // 4个数据的求和
        int d = 30;
        result = sum(a, b, c, d);
        System.out.println("result:" + result);
 
       需求:我要写一个求和的功能,到底是几个数据求和呢,我不太清楚,但是我知道在调用的时候我肯定就知道了
        为了解决这个问题,Java就提供了一个东西:可变参数
        result = sum(a, b, c, d, 40);
        System.out.println("result:" + result);
 
        result = sum(a, b, c, d, 40, 50);
        System.out.println("result:" + result);
    }
 
    public static int sum(int... a) {
        // System.out.println(a);
        //return 0;
 
        int s = 0;
        //在这里,其实a是一个数组
        for(int x : a){
            s +=x;
        }
 
        return s;
    }
通过反编译发现,其实还是数组
 
 12.Arrays工具类的asList()方法(接收可变参数)
 public static <T> List<T> asList(T... a):把数组转成集合
注释:第一个<T>表示这是一个泛型方法名叫asList
            第二个<T>表示返回值是一个泛型接口---List<T>
public static void main(String[] args) {
        // 定义一个数组
        // String[] strArray = { "hello", "world", "java" };
        // List<String> list = Arrays.asList(strArray);
 
        List<String> list = Arrays.asList("hello", "world", "java");
        // UnsupportedOperationException
        // list.add("javaee");
        // UnsupportedOperationException
        // list.remove(1);
        list.set(1, "javaee");
 
        for (String s : list) {
            System.out.println(s);
        }
    }
注意事项:
       虽然可以把数组转成集合,但是集合的长度不能改变
asList接收可变参数,Arrays.asList("hello", "world", "java");//可以
                               Arrays.asList("hello", "world");//也可以
 
13.一个案例:集合嵌套存储和遍历元素的案例
集合的嵌套遍历
  需求:
          我们班有学生,每一个学生是不是一个对象。所以我们可以使用一个集合表示我们班级的学生。ArrayList<Student>
         但是呢,我们旁边是不是还有班级,每个班级是不是也是一个ArrayList<Student>。
         而我现在有多个ArrayList<Student>。也要用集合存储,怎么办呢?
          就是这个样子的:ArrayList<ArrayList<Student>>
 
 
案例图解
 
public static void main(String[] args) {
        // 创建大集合
        ArrayList<ArrayList<Student>> bigArrayList = new ArrayList<ArrayList<Student>>();
 
        // 创建第一个班级的学生集合
        ArrayList<Student> firstArrayList = new ArrayList<Student>();
        // 创建学生
        Student s1 = new Student("唐僧", 30);
        Student s2 = new Student("孙悟空", 29);
        Student s3 = new Student("猪八戒", 28);
        Student s4 = new Student("沙僧", 27);
        Student s5 = new Student("白龙马", 26);
        // 学生进班
        firstArrayList.add(s1);
        firstArrayList.add(s2);
        firstArrayList.add(s3);
        firstArrayList.add(s4);
        firstArrayList.add(s5);
        // 把第一个班级存储到学生系统中
        bigArrayList.add(firstArrayList);
 
        // 创建第二个班级的学生集合
        ArrayList<Student> secondArrayList = new ArrayList<Student>();
        // 创建学生
        Student s11 = new Student("诸葛亮", 30);
        Student s22 = new Student("司马懿", 28);
        Student s33 = new Student("周瑜", 26);
        // 学生进班
        secondArrayList.add(s11);
        secondArrayList.add(s22);
        secondArrayList.add(s33);
        // 把第二个班级存储到学生系统中
        bigArrayList.add(secondArrayList);
 
        // 创建第三个班级的学生集合
        ArrayList<Student> thirdArrayList = new ArrayList<Student>();
        // 创建学生
        Student s111 = new Student("宋江", 40);
        Student s222 = new Student("吴用", 35);
        Student s333 = new Student("高俅", 30);
        Student s444 = new Student("李师师", 22);
        // 学生进班
        thirdArrayList.add(s111);
        thirdArrayList.add(s222);
        thirdArrayList.add(s333);
        thirdArrayList.add(s444);
        // 把第三个班级存储到学生系统中
        bigArrayList.add(thirdArrayList);
 
        // 遍历集合
        for (ArrayList<Student> array : bigArrayList) {
            for (Student s : array) {
                System.out.println(s.getName() + "---" + s.getAge());
            }
        }
    }
 
14.第二个案例
 
获取10个1-20之间的随机数,要求不能重复
 
用数组实现,但是数组的长度是固定的,长度不好确定
  所以我们使用集合实现
  
  分析:
          A:创建产生随机数的对象
         B:创建一个存储随机数的集合。
          C:定义一个统计变量。从0开始。
          D:判断统计遍历是否小于10
              是:先产生一个随机数,判断该随机数在集合中是否存在。
                      如果不存在:就添加,统计变量++。
                      如果存在:就不搭理它。
              否:不搭理它
          E:遍历集合
 
 
实现代码参考
public static void main(String[] args) {
        // 创建产生随机数的对象
        Random r = new Random();
 
        // 创建一个存储随机数的集合。
        ArrayList<Integer> array = new ArrayList<Integer>();
 
        // 定义一个统计变量。从0开始。
        int count = 0;
 
        // 判断统计遍历是否小于10
        while (count < 10) {
            //先产生一个随机数
            int number = r.nextInt(20) + 1;
 
            //判断该随机数在集合中是否存在。
            if(!array.contains(number)){
                //如果不存在:就添加,统计变量++。
                array.add(number);
                count++;
            }
        }
 
        //遍历集合
        for(Integer i : array){
            System.out.println(i);
        }
    }
 
15.案例3
 
  需求:键盘录入多个数据,以0结束,要求在控制台输出这多个数据中的最大值
  
 分析:
          A:创建键盘录入数据对象
          B:键盘录入多个数据,我们不知道多少个,所以用集合存储
          C:以0结束,这个简单,只要键盘录入的数据是0,我就不继续录入数据了
          D:把集合转成数组
          E:对数组排序
          F:获取该数组中的最大索引的值
 
示例代码
public static void main(String[] args) {
        // 创建键盘录入数据对象
        Scanner sc = new Scanner(System.in);
 
        // 键盘录入多个数据,我们不知道多少个,所以用集合存储
        ArrayList<Integer> array = new ArrayList<Integer>();
 
        // 以0结束,这个简单,只要键盘录入的数据是0,我就不继续录入数据了
        while (true) {
            System.out.println("请输入数据:");
            int number = sc.nextInt();
            if (number != 0) {
                array.add(number);
            } else {
                break;
            }
        }
 
        // 把集合转成数组
        // public <T> T[] toArray(T[] a)
        Integer[] i = new Integer[array.size()];
        // Integer[] ii = array.toArray(i);
        array.toArray(i);
        // System.out.println(i);
        // System.out.println(ii);
 
        // 对数组排序
        // public static void sort(Object[] a)
        Arrays.sort(i);
 
        // 获取该数组中的最大索引的值
        System.out.println("数组是:" + arrayToString(i) + "最大值是:"
                + i[i.length - 1]);
    }
 
    public static String arrayToString(Integer[] i) {
        StringBuilder sb = new StringBuilder();
 
        sb.append("[");
        for (int x = 0; x < i.length; x++) {
            if (x == i.length - 1) {
                sb.append(i[x]);
            } else {
                sb.append(i[x]).append(", ");
            }
        }
        sb.append("]");
 
        return sb.toString();
    }
几个注意或者有疑问的地方
 
 
 
 
day17
 
1.(ArrayList集合的toString()方法源码解析
解析
代码:
    Collection c = new ArrayList();
    c.add("hello");
    c.add("world");
    c.add("java");
 
    System.out.println(c);
 
为什么c输出的不是地址值呢?
    A:Collection c = new ArrayList();
        这是多态,所以输出c的toString()方法,其实是输出ArrayList的toString()
    B:看ArrayList的toString()
        而我们在ArrayList里面却没有发现toString()。
        以后遇到这种情况,也不要担心,你认为有,它却没有,就应该去它父亲里面看看。
    C:toString()的方法源码
 
        public String toString() {
            Iterator<E> it = iterator(); //集合本身调用迭代器方法,得到集合迭代器
            if (! it.hasNext())
                return "[]";
 
            StringBuilder sb = new StringBuilder();
            sb.append('[');
            for (;;) {
                E e = it.next(); //e=hello,world,java
                sb.append(e == this ? "(this Collection)" : e);
                if (! it.hasNext())
                    //[hello, world, java]
                    return sb.append(']').toString();
                sb.append(',').append(' ');
            }
        }
 
2.用户登录注册案例
 
part1:分析图解
part2:用户登录注册案例分析
需求:用户登录注册案例。
 
按照如下的操作,可以让我们更符号面向对象思想
    A:有哪些类呢?
    B:每个类有哪些东西呢?
    C:类与类之间的关系是什么呢?
 
分析:
    A:有哪些类呢?
        用户类
        测试类
    B:每个类有哪些东西呢?
        用户类:
            成员变量:用户名,密码
            构造方法:无参构造
            成员方法:getXxx()/setXxx()
                       登录,注册
 
            假如用户类的内容比较对,将来维护起来就比较麻烦,为了更清晰的分类,我们就把用户又划分成了两类
                用户基本描述类
                    成员变量:用户名,密码
                    构造方法:无参构造
                    成员方法:getXxx()/setXxx()
                用户操作类
                    登录,注册
        测试类:
            main方法。
    C:类与类之间的关系是什么呢?
        在测试类中创建用户操作类和用户基本描述类的对象,并使用其功能。
 
分包:
    A:功能划分
    B:模块划分
    C:先按模块划分,再按功能划分
 
今天我们选择按照功能划分:
    用户基本描述类包 cn.itcast.pojo
    用户操作接口 cn.itcast.dao
    用户操作类包 cn.itcast.dao.impl
        今天是集合实现,过几天是IO实现,再过几天是GUI实现,就业班我们就是数据库实现
    用户测试类 cn.itcast.test
 
part3:用户登录注册案例用户基本描述类用户操作接口的实现
  新建一个包  cn.itcast.pojo
=============分割线==============
package cn.itcast.pojo;
 
/**
 * 这是用户基本描述类
 * 
 * @author 风清扬
 * @version V1.0
 * 
 */
public class User {
    // 用户名
    private String username;
    // 密码
    private String password;
 
    public User() {
    }
 
    public String getUsername() {
        return username;
    }
 
    public void setUsername(String username) {
        this.username = username;
    }
 
    public String getPassword() {
        return password;
    }
 
    public void setPassword(String password) {
        this.password = password;
    }
}
 
============分割线==================
再新建一个包 cn.itcast.dao
 
========分割线===============
package cn.itcast.dao;
 
import cn.itcast.pojo.User;
 
/**
 * 这是针对用户进行操作的接口
 * 
 * @author 风清扬
 * @version V1.0
 * 
 */
public interface UserDao {
    /**
     * 这是用户登录功能
     * 
     * @param username
     *            用户名
     * @param password
     *            密码
     * @return 返回登录是否成功
     */
    public abstract boolean isLogin(String username, String password);
 
    /**
     * 这是用户注册功能
     * 
     * @param user
     *            要注册的用户信息
     */
    public abstract void regist(User user);
}
========分割线==========================
两个注意问题
 
再新建一个包 cn.itcast.dao.impl  
UserDaoImpl.java
============分割线=================
package cn.itcast.dao.impl;
 
import java.util.ArrayList;
 
import cn.itcast.dao.UserDao;
import cn.itcast.pojo.User;
 
/**
 * 这是用户操作的具体实现类(集合版)
 * 
 * @author 风清扬
 * @version V1.0
 * 
 */
public class UserDaoImpl implements UserDao {
    // 为了让多个方法能够使用同一个集合,就把集合定义为成员变量
    // 为了不让外人看到,用private
    // 为了让多个对象共享同一个成员变量,用static
    private static ArrayList<User> array = new ArrayList<User>();
 
    @Override
    public boolean isLogin(String username, String password) {
        // 遍历集合,获取每一个用户,并判断该用户的用户名和密码是否和传递过来的匹配
        boolean flag = false;
 
        for (User u : array) {
            if (u.getUsername().equals(username)
                    && u.getPassword().equals(password)) {
                flag = true;
                break;
            }
        }
 
        return flag;
    }
 
    @Override
    public void regist(User user) {
        // 把用户信息存储集合
        // ArrayList<User> array = new ArrayList<User>();
        array.add(user);
    }
}
 
===========分割线================
 
再新建一个包 cn.itcast.test
UserTest.java

 

==========分割线====================
package cn.itcast.test;
 
import java.util.Scanner;
 
import cn.itcast.dao.UserDao;
import cn.itcast.dao.impl.UserDaoImpl;
import cn.itcast.game.GuessNumber;
import cn.itcast.pojo.User;
 
/**
 * 用户测试类
 * 
 * @author 风清扬
 * @version V1.0
 * 
 *          新增加了两个小问题 A:多个对象共享同一个成员变量,用静态
 *          B:循环里面如果有switch,并且在switch里面有break,那么结束的不是循环,而是switch语句
 * 
 */
public class UserTest {
    public static void main(String[] args) {
        // 为了能够回来
        while (true) {
            // 欢迎界面,给出选择项
            System.out.println("--------------欢迎光临--------------");
            System.out.println("1 登录");
            System.out.println("2 注册");
            System.out.println("3 退出");
            System.out.println("请输入你的选择:");
            // 键盘录入选择,根据选择做不同的操作
            Scanner sc = new Scanner(System.in);
            // 为了后面的录入信息的方便,我所有的数据录入全部用字符接收
            String choiceString = sc.nextLine();
 
            // switch语句的多个地方要使用,我就定义到外面
            UserDao ud = new UserDaoImpl();
 
            // 经过简单的思考,我选择了switch,而且是JDK1.7以及以后才能用,因为switch接收了字符串
            switch (choiceString) {
            case "1":
                // 登录界面,请输入用户名和密码
                System.out.println("--------------登录界面--------------");
                System.out.println("请输入用户名:");
                String username = sc.nextLine();
                System.out.println("请输入密码:");
                String password = sc.nextLine();
 
                // 调用登录功能
                // UserDao ud = new UserDaomImpl();
 
                boolean flag = ud.isLogin(username, password);
                if (flag) {
                    System.out.println("登录成功,可以开始玩游戏了");
 
                    System.out.println("你玩吗?y/n");
                    while (true) {
                        String resultString = sc.nextLine();
                        if (resultString.equalsIgnoreCase("y")) {
                            // 玩游戏
                            GuessNumber.start();
                            System.out.println("你还玩吗?y/n");
                        } else {
                            break;
                        }
                    }
                    System.out.println("谢谢使用,欢迎下次再来");
                    System.exit(0);
                    // break; //这里写break,结束的是switch
                } else {
                    System.out.println("用户名或者密码有误,登录失败");
                }
                break;
            case "2":
                // 欢迎界面,请输入用户名和密码
                System.out.println("--------------注册界面--------------");
                System.out.println("请输入用户名:");
                String newUsername = sc.nextLine();
                System.out.println("请输入密码:");
                String newPassword = sc.nextLine();
 
                // 把用户名和密码封装到一个对象中
                User user = new User();
                user.setUsername(newUsername);
                user.setPassword(newPassword);
 
                // 调用注册功能
                // 多态
                // UserDao ud = new UserDaoImpl();
                // 具体类使用
                // UserDaoImpl udi = new UserDaoImpl();
 
                ud.regist(user);
                System.out.println("注册成功");
                break;
            case "3":
            default:
                System.out.println("谢谢使用,欢迎下次再来");
                System.exit(0);
                //break;
            }
        }
    }
}
===============分割线===================
3.Set集合概述及特点
Collection
 *         |--List
 *             有序(存储顺序和取出顺序一致),可重复
 *         |--Set
 *             无序(存储顺序和取出顺序不一致),唯一
 * 
 * HashSet:它不保证 set 的迭代顺序;特别是它不保证该顺序恒久不变。
 * 注意:虽然Set集合的元素无序,但是,作为集合来说,它肯定有它自己的存储顺序,
 * 而你的顺序恰好和它的存储顺序一致,这代表不了有序,你可以多存储一些数据,就能看到效果。
 
4.HashSet集合的add()方法的源码以及解析
 HashSet:存储字符串并遍历
 * 问题:为什么存储字符串的时候,字符串内容相同的只存储了一个呢?
 
interface Collection {
    ...
}
 
interface Set extends Collection {
    ...
}
 
class HashSet implements Set {
    private static final Object PRESENT = new Object();
    private transient HashMap<E,Object> map;
 
    public HashSet() {
        map = new HashMap<>();
    }
 
    public boolean add(E e) { //e=hello,world
        return map.put(e, PRESENT)==null;
    }
}
 
class HashMap implements Map {
    public V put(K key, V value) { //key=e=hello,world
 
        //看哈希表是否为空,如果空,就开辟空间
        if (table == EMPTY_TABLE) {
            inflateTable(threshold);
        }
 
        //判断对象是否为null
        if (key == null)
            return putForNullKey(value);
 
        int hash = hash(key); //和对象的hashCode()方法相关
 
        //在哈希表中查找hash值
        int i = indexFor(hash, table.length);
        for (Entry<K,V> e = table[i]; e != null; e = e.next) {
            //这次的e其实是第一次的world
            Object k;
            if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
                V oldValue = e.value;
                e.value = value;
                e.recordAccess(this);
                return oldValue;
                //走这里其实是没有添加元素
            }
        }
 
        modCount++;
        addEntry(hash, key, value, i); //把元素添加
        return null;
    }
 
    transient int hashSeed = 0;
 
    final int hash(Object k) { //k=key=e=hello,
        int h = hashSeed;
        if (0 != h && k instanceof String) {
            return sun.misc.Hashing.stringHash32((String) k);
        }
 
        h ^= k.hashCode(); //这里调用的是对象的hashCode()方法
 
        // This function ensures that hashCodes that differ only by
        // constant multiples at each bit position have a bounded
        // number of collisions (approximately 8 at default load factor).
        h ^= (h >>> 20) ^ (h >>> 12);
        return h ^ (h >>> 7) ^ (h >>> 4);
    }
}
 
 
hs.add("hello");
hs.add("world");
hs.add("java");
hs.add("world");
 
总结:通过查看add方法的源码,我们知道这个方法底层依赖 两个方法:hashCode()和equals()。
 * 步骤:
 *         首先比较哈希值
 *         如果相同,继续走,比较地址值或者走equals()
 *         如果不同,就直接添加到集合中    
 * 按照方法的步骤来说:    
 *         先看hashCode()值是否相同
 *             相同:继续走equals()方法
 *                 返回true:    说明元素重复,就不添加
 *                 返回false:说明元素不重复,就添加到集合
 *             不同:就直接把元素添加到集合
 * 如果类没有重写这两个方法,默认使用的Object()。一般来说不会相同。
 * 而String类重写了hashCode()和equals()方法,所以,它就可以把内容相同的字符串去掉。只留下一个。
 
以下两个重写都在学生类Student类中修改
重写hashCode方法

      重写equals方法

需要手动重写的代码如下
 @Override
         public int hashCode() {
         // return 0;
         // 因为成员变量值影响了哈希值,所以我们把成员变量值相加即可
         // return this.name.hashCode() + this.age;
         // 看下面
         // s1:name.hashCode()=40,age=30
         // s2:name.hashCode()=20,age=50
         // 尽可能的区分,我们可以把它们乘以一些整数(乘上整数扩大分差把细微差别放大避免偶尔误差)
         return this.name.hashCode() + this.age * 15;
         }
 
         @Override
         public boolean equals(Object obj) {
         // System.out.println(this + "---" + obj);//测试比较顺序以及比较次数的代码,测试后注释掉
         if (this == obj) {
         return true;
         }
 
         if (!(obj instanceof Student)) {
         return false;
         }
 
         Student s = (Student) obj;
         return this.name.equals(s.name) && this.age == s.age;
         }
@Override
         public String toString() {
         return "Student [name=" + name + ", age=" + age + "]";
         }
优化测试截图(优化前hashCode默认返回值是0.也就是所有的元素哈希值都一样)
优化前,比较次数比较大

 优化后(哈希值不再一样,通过哈希值与成员变量相加来重写hashCode方法避免不必要的比较)

但实际上,一般不自己想写这么麻烦,可以用代码自动生成功能来实现

 

 

以后解决HashSet 存储自定义对象时元素不唯一问题就可以用重写hashCode()方法和equals()方法解决

 

5.HashSet集合存储自定义对象并遍历
如果对象的成员变量值相同即为同一个对象
 
注意了:
 *         你使用的是HashSet集合,这个集合的底层是哈希表结构。
 *         而哈希表结构底层依赖:hashCode()和equals()方法。
 *         如果你认为对象的成员变量值相同即为同一个对象的话,你就应该重写这两个方法。
 *         如何重写呢?不同担心,自动生成即可。
 
import java.util.HashSet;
 
public class DogDemo {
    public static void main(String[] args) {
        HashSet<Dog> hs = new HashSet<Dog>();
 
        Dog d1 = new Dog("网", 27, "绿色", '男');
        Dog d2 = new Dog("随", 27, "绿色", '男');
        Dog d3 = new Dog("王", 27, "绿色", '男');
        Dog d4 = new Dog("网", 27, "绿色", '男');
        Dog d5 = new Dog("网", 27, "绿色", '女');
 
        hs.add(d1);
        hs.add(d2);
        hs.add(d3);
        hs.add(d4);
        hs.add(d5);
 
        for (Dog d : hs) {
            System.out.println(d.getName() + "---" + d.getAge() + "---" + d.getColor() + "---" + d.getSex());
        }
 
    }
}
 
Dog类
public class Dog {
    private String name;
    private int age;
    private String color;
    private char sex;
 
    public Dog() {
        super();
        // TODO Auto-generated constructor stub
    }
 
    public Dog(String name, int age, String color, char sex) {
        super();
        this.name = name;
        this.age = age;
        this.color = color;
        this.sex = sex;
    }
 
    public String getName() {
        return name;
    }
 
    public void setName(String name) {
        this.name = name;
    }
 
    public int getAge() {
        return age;
    }
 
    public void setAge(int age) {
        this.age = age;
    }
 
    public String getColor() {
        return color;
    }
 
    public void setColor(String color) {
        this.color = color;
    }
 
    public char getSex() {
        return sex;
    }
 
    public void setSex(char sex) {
        this.sex = sex;
    }
 
    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + age;
        result = prime * result + ((color == null) ? 0 : color.hashCode());
        result = prime * result + ((name == null) ? 0 : name.hashCode());
        result = prime * result + sex;
        return result;
    }
 
    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Dog other = (Dog) obj;
        if (age != other.age)
            return false;
        if (color == null) {
            if (other.color != null)
                return false;
        } else if (!color.equals(other.color))
            return false;
        if (name == null) {
            if (other.name != null)
                return false;
        } else if (!name.equals(other.name))
            return false;
        if (sex != other.sex)
            return false;
        return true;
    }
 
}
6.TreeSet
TreeSet:能够对元素按照某种规则进行排序。
排序有两种方式
 * A:自然排序
 * B:比较器排序
 * 
 * TreeSet集合的特点:排序和唯一
 * 
 * 通过观察TreeSet的add()方法,我们知道最终要看TreeMap的put()方法。
 
7.TreeSet保证元素排序的源码解析
interface Collection {...}
 
interface Set extends Collection {...}
 
interface NavigableMap {
 
}
 
class TreeMap implements NavigableMap {
     public V put(K key, V value) {
        Entry<K,V> t = root;
        if (t == null) {
            compare(key, key); // type (and possibly null) check
 
            root = new Entry<>(key, value, null);
            size = 1;
            modCount++;
            return null;
        }
        int cmp;
        Entry<K,V> parent;
        // split comparator and comparable paths
        Comparator<? super K> cpr = comparator;
        if (cpr != null) {
            do {
                parent = t;
                cmp = cpr.compare(key, t.key);
                if (cmp < 0)
                    t = t.left;
                else if (cmp > 0)
                    t = t.right;
                else
                    return t.setValue(value);
            } while (t != null);
        }
        else {
            if (key == null)
                throw new NullPointerException();
            Comparable<? super K> k = (Comparable<? super K>) key;
            do {
                parent = t;
                cmp = k.compareTo(t.key);
                if (cmp < 0)
                    t = t.left;
                else if (cmp > 0)
                    t = t.right;
                else
                    return t.setValue(value);
            } while (t != null);
        }
        Entry<K,V> e = new Entry<>(key, value, parent);
        if (cmp < 0)
            parent.left = e;
        else
            parent.right = e;
        fixAfterInsertion(e);
        size++;
        modCount++;
        return null;
    }
}
 
class TreeSet implements Set {
    private transient NavigableMap<E,Object> m;
 
    public TreeSet() {
         this(new TreeMap<E,Object>());
    }
 
    public boolean add(E e) {
        return m.put(e, PRESENT)==null;
    }
}
 
真正的比较是依赖于元素的compareTo()方法,而这个方法是定义在 Comparable里面的。
所以,你要想重写该方法,就必须是先 实现Comparable接口。这个接口表示的就是自然排序
 
附:TreeSet保证元素唯一性和自然排序的原理和图解
7.TreeSet存储自定义对象并遍历练习1
 
下面贴代码
TreeSetDemo2.java
===============分割线===================
import java.util.TreeSet;
 
/*
 * TreeSet存储自定义对象并保证排序和唯一。
 * 
 * A:你没有告诉我们怎么排序
 *         自然排序,按照年龄从小到大排序
 * B:元素什么情况算唯一你也没告诉我
 *         成员变量值都相同即为同一个元素
 */
public class TreeSetDemo2 {
    public static void main(String[] args) {
        // 创建集合对象
        TreeSet<Student> ts = new TreeSet<Student>();
 
        // 创建元素
        Student s1 = new Student("linqingxia", 27);
        Student s2 = new Student("zhangguorong", 29);
        Student s3 = new Student("wanglihong", 23);
        Student s4 = new Student("linqingxia", 27);
        Student s5 = new Student("liushishi", 22);
        Student s6 = new Student("wuqilong", 40);
        Student s7 = new Student("fengqingy", 22);
 
        // 添加元素
        ts.add(s1);
        ts.add(s2);
        ts.add(s3);
        ts.add(s4);
        ts.add(s5);
        ts.add(s6);
        ts.add(s7);
 
        // 遍历
        for (Student s : ts) {
            System.out.println(s.getName() + "---" + s.getAge());
        }
    }
}
==============分割线==============
Student类
Student.java
==============分割线==============
 
/*
 * 如果一个类的元素要想能够进行自然排序,就必须实现自然排序接口
 */
public class Student implements Comparable<Student> {
    private String name;
    private int age;
 
    public Student() {
        super();
    }
 
    public Student(String name, int age) {
        super();
        this.name = name;
        this.age = age;
    }
 
    public String getName() {
        return name;
    }
 
    public void setName(String name) {
        this.name = name;
    }
 
    public int getAge() {
        return age;
    }
 
    public void setAge(int age) {
        this.age = age;
    }
 
    @Override
    public int compareTo(Student s) {
        // return 0;
        // return 1;
        // return -1;
 
        // 这里返回什么,其实应该根据我的排序规则来做
        // 按照年龄排序,主要条件
        int num = this.age - s.age;
        // 次要条件
        // 年龄相同的时候,还得去看姓名是否也相同
        // 如果年龄和姓名都相同,才是同一个元素
        //String默认已经实现了Comparable接口,所以可以大胆用compareTo方法
        int num2 = num == 0 ? this.name.compareTo(s.name) : num;
        return num2;
    }
}
 
下面是以上代码的解析。
 
附:A:首先解析以下这行代码
     int num2 = num == 0 ? this.name.compareTo(s.name) : num;
解:这行语句是三目运算符,意思是先比较主要条件---年龄,num为年龄比较产生的返回值,如果是零就不插入二叉树(TreeSet)中(通过比较发现年龄重复就不添加),如果此时直接返回num的话会造成Student对象的意外丢失(例如年龄相同但实际上姓名不相同的学生对象),
 
因此为了解决这个问题,新添加了num2,考虑多了次要条件姓名,如果年龄相同的同时姓名也相同就返回num2的值0,代表不添加元素到二叉树中。
 
B:String默认已经实现了Comparable接口
 
C:为什么要在自定义类Student中实现Comparable接口呢?(implements Comparable<T>)
如果不实现这个接口,运行如下
 
查API
 
由上图可知:实现这个借口是为了进行自然排序。Student类默认并没有实现Comparable接口
 
Comparable接口 只有一个compareTo方法,实现接口时需要重写这个方法
 
8.TreeSet存储自定义对象并遍历练习2
先贴代码
==============分割线=======================
import java.util.TreeSet;
 
/*
 * 需求:请按照姓名的长度排序
 */
public class TreeSetDemo {
    public static void main(String[] args) {
        // 创建集合对象
        TreeSet<Student> ts = new TreeSet<Student>();
 
        // 创建元素
        Student s1 = new Student("linqingxia", 27);
        Student s2 = new Student("zhangguorong", 29);
        Student s3 = new Student("wanglihong", 23);//s1与s3名字长度相同
        Student s4 = new Student("linqingxia", 27);
        Student s5 = new Student("liushishi", 22);
        Student s6 = new Student("wuqilong", 40);
        Student s7 = new Student("fengqingy", 22);
        Student s8 = new Student("linqingxia", 29);
 
        // 添加元素
        ts.add(s1);
        ts.add(s2);
        ts.add(s3);
        ts.add(s4);
        ts.add(s5);
        ts.add(s6);
        ts.add(s7);
        ts.add(s8);
 
        // 遍历
        for (Student s : ts) {
            System.out.println(s.getName() + "---" + s.getAge());
        }
    }
}
 
=================分割线=====================
Student类
 
/*
 * 如果一个类的元素要想能够进行自然排序,就必须实现自然排序接口
 */
public class Student implements Comparable<Student> {
    private String name;
    private int age;
 
    public Student() {
        super();
    }
 
    public Student(String name, int age) {
        super();
        this.name = name;
        this.age = age;
    }
 
    public String getName() {
        return name;
    }
 
    public void setName(String name) {
        this.name = name;
    }
 
    public int getAge() {
        return age;
    }
 
    public void setAge(int age) {
        this.age = age;
    }
 
    @Override
    public int compareTo(Student s) {
        // 主要条件 姓名的长度
        int num = this.name.length() - s.name.length();
        // 姓名的长度相同,不代表姓名的内容相同
        int num2 = num == 0 ? this.name.compareTo(s.name) : num;
        // 姓名的长度和内容相同,不代表年龄相同,所以还得继续判断年龄
        int num3 = num2 == 0 ? this.age - s.age : num2;
        return num3;
    }
}
 
留意看上面stuedent类中的compareTo方法,虽然需求中只说明了按照姓名的长度排序,但是隐含的比较,隐含的条件(如姓名的内容,年龄是否相同)却是不能忽略的!
 
9.TreeSet保证元素唯一性和比较器排序的原理及代码实现
 
TreeSet集合保证元素排序和唯一性的原理
 * 唯一性:是根据比较的返回是否是0来决定。
 * 排序:
 *         A:自然排序(元素具备比较性)
 *             让元素所属的类实现自然排序接口 Comparable
 *         B:比较器排序(集合具备比较性)
 *             让集合的构造方法接收一个比较器接口的子类对象 Comparator
 
查API-----TreeSet  比较器排序  带参构造方法

 

 

首先,惯例新建一个TreeSetDemo
=========分割线==========
import java.util.Comparator;
import java.util.TreeSet;
 
/*
 * 需求:请按照姓名的长度排序
 */
public class TreeSetDemo {
    public static void main(String[] args) {
        // 创建集合对象
        // TreeSet<Student> ts = new TreeSet<Student>(); //自然排序
        // public TreeSet(Comparator comparator) //比较器排序
        TreeSet<Student> ts = new TreeSet<Student>(new MyComparator());
 
        // 创建元素
        Student s1 = new Student("linqingxia", 27);
        Student s2 = new Student("zhangguorong", 29);
        Student s3 = new Student("wanglihong", 23);
        Student s4 = new Student("linqingxia", 27);
        Student s5 = new Student("liushishi", 22);
        Student s6 = new Student("wuqilong", 40);
        Student s7 = new Student("fengqingy", 22);
        Student s8 = new Student("linqingxia", 29);
 
        // 添加元素
        ts.add(s1);
        ts.add(s2);
        ts.add(s3);
        ts.add(s4);
        ts.add(s5);
        ts.add(s6);
        ts.add(s7);
        ts.add(s8);
 
        // 遍历
        for (Student s : ts) {
            System.out.println(s.getName() + "---" + s.getAge());
        }
    }
}
===========分割线===============
在同一个包下定义一个Student类
================分割线======================
public class Student {
    private String name;
    private int age;
 
    public Student() {
        super();
    }
 
    public Student(String name, int age) {
        super();
        this.name = name;
        this.age = age;
    }
 
    public String getName() {
        return name;
    }
 
    public void setName(String name) {
        this.name = name;
    }
 
    public int getAge() {
        return age;
    }
 
    public void setAge(int age) {
        this.age = age;
    }
}
 
================分割线================
 
最后,同一个包下定义一个MyComparator类

 

 

import java.util.Comparator;
 
public class MyComparator implements Comparator<Student> {
 
    @Override
    public int compare(Student s1, Student s2) {
        // int num = this.name.length() - s.name.length();
        // this -- s1
        // s -- s2
        // 姓名长度
        int num = s1.getName().length() - s2.getName().length();
        // 姓名内容
        int num2 = num == 0 ? s1.getName().compareTo(s2.getName()) : num;
        // 年龄
        int num3 = num2 == 0 ? s1.getAge() - s2.getAge() : num2;
        return num3;
    }
 
}
 
以下为一些解析说明
A:上面专门定义了一个类MyComparator,其实也可以省略这一个类,直接在TreeSetDemo测试类中定义
一个匿名内部类
如下
TreeSetDemo.java
=================分割线========================
import java.util.Comparator;
import java.util.TreeSet;
 
 
public class TreeSetDemo {
    public static void main(String[] args) {
        // 创建集合对象
        // TreeSet<Student> ts = new TreeSet<Student>(); //自然排序
        // public TreeSet(Comparator comparator) //比较器排序
        // TreeSet<Student> ts = new TreeSet<Student>(new MyComparator());
 
        // 如果一个方法的参数是接口,那么真正要的是接口的实现类的对象
        // 而匿名内部类就可以实现这个东西
        TreeSet<Student> ts = new TreeSet<Student>(new Comparator<Student>() {
            @Override
            public int compare(Student s1, Student s2) {
                // 姓名长度
                int num = s1.getName().length() - s2.getName().length();
                // 姓名内容
                int num2 = num == 0 ? s1.getName().compareTo(s2.getName())
                        : num;
                // 年龄
                int num3 = num2 == 0 ? s1.getAge() - s2.getAge() : num2;
                return num3;
            }
        });
 
        // 创建元素
        Student s1 = new Student("linqingxia", 27);
        Student s2 = new Student("zhangguorong", 29);
        Student s3 = new Student("wanglihong", 23);
        Student s4 = new Student("linqingxia", 27);
        Student s5 = new Student("liushishi", 22);
        Student s6 = new Student("wuqilong", 40);
        Student s7 = new Student("fengqingy", 22);
        Student s8 = new Student("linqingxia", 29);
 
        // 添加元素
        ts.add(s1);
        ts.add(s2);
        ts.add(s3);
        ts.add(s4);
        ts.add(s5);
        ts.add(s6);
        ts.add(s7);
        ts.add(s8);
 
        // 遍历
        for (Student s : ts) {
            System.out.println(s.getName() + "---" + s.getAge());
        }
    }
}
 
===============分割线=======================
B:在MyComparator类 中getName(),getAge()与this.name 和this.age 问题
 
外部类不能访问private修饰的成员变量
C:注意两个不同的接口以及它们的方法
 
接口 Comparable======方法compareTo
接口 Comparator ==== 方法compare
* TreeSet集合保证元素排序和唯一性的原理
 * 唯一性:是根据比较的返回是否是0来决定。
 * 排序:
 *         A:自然排序(元素具备比较性)(Student类实现比较接口)
 *             让元素所属的类实现自然排序接口 Comparable
 *         B:比较器排序(集合具备比较性)(也就是说,Student类不需要实现任何接口)
 *             让集合的构造方法接收一个比较器接口的子类对象 Comparator
 
 
10.一个案例----编写一个程序,获取10个1至20的随机数,要求随机数不能重复
 
import java.util.HashSet;
import java.util.Random;
 
/*
 * 编写一个程序,获取10个1至20的随机数,要求随机数不能重复。
 * 
 * 分析:
 *         A:创建随机数对象
 *         B:创建一个HashSet集合
 *         C:判断集合的长度是不是小于10
 *             是:就创建一个随机数添加
 *             否:不搭理它
 *         D:遍历HashSet集合
 */
public class HashSetDemo {
    public static void main(String[] args) {
        // 创建随机数对象
        Random r = new Random();
 
        // 创建一个Set集合
        HashSet<Integer> ts = new HashSet<Integer>();//Integer默认已经实现了比较接口Comparable
 
        // 判断集合的长度是不是小于10
        while (ts.size() < 10) {
            int num = r.nextInt(20) + 1;
            ts.add(num);
        }
 
        // 遍历Set集合
        for (Integer i : ts) {
            System.out.println(i);
        }
    }
}
 
 
11.一个案例----键盘录入5个学生信息(姓名,语文成绩,数学成绩,英语成绩),按照总分从高到低输出到控制台
TreeSetDemo .java
import java.util.Comparator;
import java.util.Scanner;
import java.util.TreeSet;
 
/*
 * 键盘录入5个学生信息(姓名,语文成绩,数学成绩,英语成绩),按照总分从高到低输出到控制台
 * 
 * 分析:
 *         A:定义学生类
 *         B:创建一个TreeSet集合
 *         C:总分从高到底如何实现呢?        
 *         D:键盘录入5个学生信息
 *         E:遍历TreeSet集合
 */
public class TreeSetDemo {
    public static void main(String[] args) {
        // 创建一个TreeSet集合
        TreeSet<Student> ts = new TreeSet<Student>(new Comparator<Student>() {
            @Override
            public int compare(Student s1, Student s2) {
                // 总分从高到低
                int num = s2.getSum() - s1.getSum();//s1与s2的位置已互换,因为成绩从高到低而不是默认的从低到高
                // 总分相同的不一定语文相同
                int num2 = num == 0 ? s1.getChinese() - s2.getChinese() : num;
                // 总分相同的不一定数序相同
                int num3 = num2 == 0 ? s1.getMath() - s2.getMath() : num2;
                // 总分相同的不一定英语相同
                int num4 = num3 == 0 ? s1.getEnglish() - s2.getEnglish() : num3;
                // 姓名还不一定相同呢
                int num5 = num4 == 0 ? s1.getName().compareTo(s2.getName())
                        : num4;
                return num5;
            }
        });
 
        System.out.println("学生信息录入开始");
        // 键盘录入5个学生信息
        for (int x = 1; x <= 5; x++) {
            Scanner sc = new Scanner(System.in);
            System.out.println("请输入第" + x + "个学生的姓名:");
            String name = sc.nextLine();
            System.out.println("请输入第" + x + "个学生的语文成绩:");
            String chineseString = sc.nextLine();
            System.out.println("请输入第" + x + "个学生的数学成绩:");
            String mathString = sc.nextLine();
            System.out.println("请输入第" + x + "个学生的英语成绩:");
            String englishString = sc.nextLine();
 
            // 把数据封装到学生对象中
            Student s = new Student();
            s.setName(name);
            s.setChinese(Integer.parseInt(chineseString));
            s.setMath(Integer.parseInt(mathString));
            s.setEnglish(Integer.parseInt(englishString));
 
            // 把学生对象添加到集合
            ts.add(s);
        }
        System.out.println("学生信息录入完毕");
 
        System.out.println("学习信息从高到低排序如下:");
        System.out.println("姓名\t语文成绩\t数学成绩\t英语成绩");
        // 遍历集合
        for (Student s : ts) {
            System.out.println(s.getName() + "\t" + s.getChinese() + "\t"
                    + s.getMath() + "\t" + s.getEnglish());
        }
    }
}
 
===================================================
Student类
 
public class Student {
    // 姓名
    private String name;
    // 语文成绩
    private int chinese;
    // 数学成绩
    private int math;
    // 英语成绩
    private int english;
 
    public Student(String name, int chinese, int math, int english) {
        super();
        this.name = name;
        this.chinese = chinese;
        this.math = math;
        this.english = english;
    }
 
    public Student() {
        super();
    }
 
    public String getName() {
        return name;
    }
 
    public void setName(String name) {
        this.name = name;
    }
 
    public int getChinese() {
        return chinese;
    }
 
    public void setChinese(int chinese) {
        this.chinese = chinese;
    }
 
    public int getMath() {
        return math;
    }
 
    public void setMath(int math) {
        this.math = math;
    }
 
    public int getEnglish() {
        return english;
    }
 
    public void setEnglish(int english) {
        this.english = english;
    }
 
    public int getSum() {
        return this.chinese + this.math + this.english;
    }
}
======================================
附上解析:
 int num = s2.getSum() - s1.getSum();
但是之前是这样的
 int num = s1.getSum() - s2.getSum();
运行如下

 

成绩并没有从高到低,所以
 int num = s2.getSum() - s1.getSum();
再次运行

 

12.最后附上一个致命bug 关于eclipse:

eclispe 控制台光标位置bug
Eclipse控制台输入数据后光标直接回到行首不跳到下一行

留意光标位置,要手动移动至下一行

 
不手动移到下一行会有莫明奇妙的异常
 
day17笔记补充
A:Collection集合总结(掌握)
    Collection
        |--List    有序,可重复
            |--ArrayList
                底层数据结构是数组,查询快,增删慢。
                线程不安全,效率高
            |--Vector
                底层数据结构是数组,查询快,增删慢。
                线程安全,效率低
            |--LinkedList
                底层数据结构是链表,查询慢,增删快。
                线程不安全,效率高
        |--Set    无序,唯一
            |--HashSet
                底层数据结构是哈希表。
                如何保证元素唯一性的呢?
                    依赖两个方法:hashCode()和equals()
                    开发中自动生成这两个方法即可
                |--LinkedHashSet
                    底层数据结构是链表和哈希表
                    由链表保证元素有序
                    由哈希表保证元素唯一
            |--TreeSet
                底层数据结构是红黑树。
                如何保证元素排序的呢?
                    自然排序
                    比较器排序
                如何保证元素唯一性的呢?
                    根据比较的返回值是否是0来决定
 
B:针对Collection集合我们到底使用谁呢?(掌握)
    唯一吗?
        是:Set
            排序吗?
                是:TreeSet
                否:HashSet
        如果你知道是Set,但是不知道是哪个Set,就用HashSet。
 
        否:List
            要安全吗?
                是:Vector
                否:ArrayList或者LinkedList
                    查询多:ArrayList
                    增删多:LinkedList
        如果你知道是List,但是不知道是哪个List,就用ArrayList。
 
    如果你知道是Collection集合,但是不知道使用谁,就用ArrayList。
 
    如果你知道用集合,就用ArrayList。
 
C:在集合中常见的数据结构(掌握)
    ArrayXxx:底层数据结构是数组,查询快,增删慢
    LinkedXxx:底层数据结构是链表,查询慢,增删快
    HashXxx:底层数据结构是哈希表。依赖两个方法:hashCode()和equals()
    TreeXxx:底层数据结构是二叉树。两种方式排序:自然排序和比较器排序

 

 

posted @ 2016-02-28 17:40  黄滔1996  阅读(6340)  评论(0编辑  收藏  举报