JavaSE高级1

时间:2021-09-11 15:37:42

内部类

内部类概念:

所谓内部类(Inner Class),顾名思义,就是将一个类定义在另一个类的内部。内部的类称之为内部类。

内部类的主要特点:

内部类可以很好的实现隐藏,可以使用protected、private修饰符。

内部类可以直接访问外部类的所有成员,包括私有成员。

外部类不能直接访问内部类的成员,必须首先要建立内部类的对象才可以访问。

内部类可以解决一些问题,比如间接地去实现多继承。可以避免修改接口而实现同一个类中两种同名方法的调用。

成员内部类及应用

成员内部类特点:

成员内部类属于外部类的实例成员,成员内部类可以有public,private,default,protected

权限修饰符。在成员内部类中访问外部类的成员方法和属性,要使用“外部类名.this.成员方

法”和“外部类名.this.成员属性”的形式。

创建成员内部类的实例使用

“外部类名.内部类名 实例名 = 外部类实例名.new 内部类构造方法(参数)”的形式。

成员内部类有以下限制:

成员内部类不能和外部类重名。

不能在成员内部类中定义static属性、方法和类(static final形式的常量定义除外)。因为

一个成员内部类实例必然与一个外部类实例关联,static成员完全可以移到其外部类中去。

 package com.abc.tzy;

 public class MemberInnerClass {
 public static void main(String[] args) {
     //创建外部类对象
     Outer1 outer = new Outer1();
     //创建内部类的对象
     Outer1.Inner1 inner = outer.new Inner1();
     inner.innerShow();
     outer.outerShow();
 }
 }

 class Outer1{
     private String name = "张三";
     private int num1 = 10;
     public void outerShow(){
         System.out.println(name);
         System.out.println(num1);
 //        System.out.println(num2);//外部类不能直接访问内部类的成员
         //外部类要访问内部类成员要先产生内部类对象
         //Inner1 in = new Inner1();
         //in.innerShow();
     }
     public class Inner1{//如果内部类为私有的 那么只有外部类自己可以使用,测试类都不能使用
         private String name = "李四";
         private int num2 = 20;
         private static final int num3 =30;//静态常量在内部类中是可以的。
         //private static int num3 =30;
         //在成员内部类中不能声明静态属性和方法
         public void innerShow(){
             System.out.println(Outer1.this.name);
             System.out.println(name);
             System.out.println(num2);
             //Outer1.this.outerShow();如果有同名方法就要加外部类名.this.方法名
             outerShow();
             //成员内部类可以直接访问外部类属性和方法(包括私有)
         }
     }
 }

内部类例1

 package com.abc.tzy;
 //内部类实现多继承
 public class MultiExtendsDemo {
 public static void main(String[] args) {
     C c = new C();
     c.getInstanceA1().showA();
     c.getInstanceB1().showB();
     c.showA();
     c.showB();
 }
 }

 class A{
     public void showA(){
         System.out.println("A");
     }
 }
 class B{
     public void showB(){
         System.out.println("B");
     }
 }

 class C{
     class A1 extends A{
         public void showA(){
             super.showA();
         }
     }
     class B1 extends B{
         public void showB(){
             super.showB();
         }
     }
     public A1 getInstanceA1(){
         return new A1();
     }
     public B1 getInstanceB1(){
         return new B1();
     }
     public void showA(){
         new A1().showA();
     }
     public void showB(){
         new B1().showB();
     }
 }

内部类实现 伪多继承

 package com.abc.tzy;
 //抽象类和接口中有同名方法,使用内部类去处理
 public class Demo {
 public static void main(String[] args) {
     Son son = new Son();
     son.show();
     son.show2();
 }
 }

 abstract class Parent{
     public abstract void show();
 }
 interface IShow{
     public abstract void show();
 }
 /*
 class Son extends Parent implements IShow{
 //到底重写的是哪个不清楚除非把上面的抽象类或者接口方法改了
     @Override
     public void show() {

     }
 }
 */
 class Son extends Parent{
     @Override
     public void show() {
         System.out.println("重写抽象类里的show方法");
     }
     private class Inner2 implements IShow{
         @Override
         public void show() {
             System.out.println("重写接口中的show方法");
         }
     }
     public void show2(){
         new Inner2().show();
     }
 }

内部类对同名方法的处理

 静态内部类及应用

静态内部类特点:

使用static修饰成员内部类叫静态内部类。

静态内部类跟外部类没有任何关系,只是在生成类名和类定义时有影响。

静态内部类可以看作是与外部类平级的类。使用方式与外部类平级的类

完全相同。

创建静态内部类的实例使用:

外部类名.内部类名 实例名 = new外部类实例名.内部类名(参数)

静态内部类有以下限制:

静态内部类不能与外部类重名。

静态内部类不能访问外部类的非静态的属性和方法。外部类不能访问

内部类的非静态的属性和方法。

 package com.abc.tzy;

 public class StaticInnerClass {
     public static void main(String[] args) {
         Outer2.Inner2 inner = new Outer2.Inner2();//构造静态内部类对象
         inner.innerShow();
         System.out.println("*******");
         Outer2 outer = new Outer2();
         outer.outerShow();
 }
 }

 class Outer2{
     private String name = "张三";
     private int num1 = 10;
     private static int num3 =100;
     public void outerShow(){
         System.out.println(name);
         System.out.println(num1);
         Inner2 inner2 = new Inner2();
         System.out.println(inner2.name);
         System.out.println(inner2.num2);
     }
     public static class Inner2{
         private String name = "李四";
         private int num2 = 20;
         private static final int num3 =30;
         public void innerShow(){
             //System.out.println(Outer2.this.name);
             //静态内部类不能访问外部类的非静态成员
             System.out.println(name);
             System.out.println(num2);
             System.out.println(num3);
             System.out.println(Outer2.num3);

         }
     }
 }

静态内部类实例

匿名内部类及应用

匿名内部类特点:

匿名内部类是没有名称的内部类,没办法引用它们。必须在创建时,

作为new语句的一部分来声明并创建它们的实例。

匿名内部类必须继承一个类(抽象的、非抽象的都可以)或者实现一个接口。

如果父类(或者父接口)是抽象类,则匿名内部类必须实现其所有抽象方法。

匿名内部类中可以定义代码块,用于实例的初始化,但是不能定义静态代码块。

匿名内部类语法:

new interface/superclass(){//类体}

这种形式的new语句声明一个新的匿名类,它对一个给定的类进行扩展,

或者实现一个给定的接口,并同事创建该匿名类的一个新实例。

 package com.abc.tzy;

 public class AnonymousInnerClass {
 public static void main(String[] args) {
     Person p = new Person();
     Dog d = new Dog();
     p.feed(d);
     //匿名类
     p.feed(new Animal(){
         @Override
         public void eat() {
             System.out.println("吃鱼");
         }
     });
 //    喂同一只狗
     Animal dog = new Animal(){
         private String name = "aa";
         @Override
         public void eat() {
             System.out.println("啃骨头");
         }
         public void show(){
             System.out.println(name);
         }
     };
     p.feed(dog);
     p.feed(dog);
 //    dog.show();//转成Animal时丢失了方法
     new Animal(){
         private String name = "aa";
         /*static不可以使用*/{
             name="哈哈";
         }
         @Override
         public void eat() {
             System.out.println("啃骨头");
         }
         public void show(){
             System.out.println(name);
         }
     }.show();

 }
 }
 class Person{
     public void feed(Animal animal){
         animal.eat();
     }
 }

 //abstract class Animal{
 //    public abstract void eat();
 //}

 //class Dog extends Animal{
 //    @Override
 //    public void eat() {
 //        System.out.println("啃骨头");
 //    }
 //}
 //接口和抽象类一样
 interface Animal{
     public abstract void eat();
 }

 class Dog implements Animal{
     @Override
     public void eat() {
         System.out.println("啃骨头");
     }
 }

匿名内部类

局部内部类及应用

局部内部类特点:

定义在代码块、方法体内的类叫局部内部类。

局部内部类访问外部类的属性和方法使用“外部类名.this.属性名”和

“外部类名. this.方法名(参数)”的形式。

对外部世界完全隐藏,只能在其作用域内生成对象。

局部内部类有以下限制:

局部类不能加访问修饰符,因为它们不是类成员。

成员内部类访问作用域内的局部变量,该局部变量需要使用final修饰.

 package com.abc.tzy;

 public class LocalInnerClass {
 public static void main(String[] args) {
     Outer3 outer = new Outer3();
     outer.showOuter();
 }
 }

 class Outer3{
     private String name = "张三";
     private int num1 = 10;
     private static int num2 = 20;
     public void showOuter(){
         final int num4 = 50;
         //局部内部类不能加访问修饰符
         //Inner3 inner =new Inner3();不可以在这里产生
         class Inner3{
             private int num3 = 30;
             private int num1 = 20;
             public void showInner(){
                 System.out.println(num3);
                 System.out.println(num1);
                 System.out.println(Outer3.this.num1);
                 System.out.println(Outer3.num2);
                 System.out.println(num4);
                 //局部内部类只能访问声明其方法中的常量
             }
         }
         Inner3 inner =new Inner3();
         inner.showInner();
     }
 }

局部内部类

 package com.abc.tzy;

 import java.util.Arrays;
 /*开发一个容器来存放键值对
 建存放英文名字,值存放中文名字,
 对键值对使用内部类进行封装。
 1使用静态内部类封装键值对数据;
 2容器默认容量为5,超过就扩容其2倍。
 3通过调用entryArrays方法返回容器中的数据*/
 public class EntryDemo {
 public static void main(String[] args) {
     MyContainer container = new MyContainer();
     container.put("jack", "成龙");
     container.put("jay", "周杰伦");
     container.put("rose", "玫瑰");
     container.put("aa", "小名");
     container.put("bb", "小黄");
     container.put("cc", "小李");
     MyContainer.Entry[] entrys = container.entryArrays();
     for (MyContainer.Entry entry : entrys) {
         System.out.println(entry.getKey()+entry.getValue());
     }

 }
 }

 class MyContainer{
     //存放entry对象的数组,默认为5
     private Entry [] entrys = new Entry[5];
     private int count = 0;
     //对外提供一个接口向容器中存放封装好的数据(Entry对象)
     public void put(String key,String value){
         Entry entry = new Entry();
         entry.setKey(key);
         entry.setValue(value);
         entrys[count++]=entry;//存放entry对象到数组中
         if(count>=entrys.length){
             //数组的扩容
             int newCapacity = entrys.length*2;
             //把老数组中的数据复制到长度为newCapacity的新数组中
             entrys = Arrays.copyOf(entrys, newCapacity);
         }
     }
     //把容器中有数据的数据返回
     public Entry[] entryArrays(){
         return Arrays.copyOfRange(entrys, 0, count);
     }
     //把键值对封装在Entry对象中
     public static class Entry{
         private String key;
         private String value;
         public String getKey() {
             return key;
         }
         public void setKey(String key) {
             this.key = key;
         }
         public String getValue() {
             return value;
         }
         public void setValue(String value) {
             this.value = value;
         }

     }
 }

内部类封装案例

自动装箱和拆箱(jdk1.5后)

1、有时我们需要将int这样的基本数据类型转换为引用类型对象;

2、基本数据(Primitive)类型的自动装箱、拆箱是J2SE5.0提供的新功能,为打包基本数据类型提供了方便,但提供方便的同时隐藏了西街,

   建议在能够区分基本数据类型与引用类型的差别时再使用;

3、一个自动装箱的例子:       Integer i = 10;  相当于Integer  i = new Integer(10);

①进行编译时,编译器根据语句上下文判断是否进行自动装箱动作。在上例中变量i引用的是Integer类的实例。

②同样的动作使用于boolean、byte、short、  char、  long、  float、double等基本数据类型,分别使用对应的包装类型(Wrapper Types)

           Boolean、Byte、Short、character、Long、Float、Double

4、J2SE5.0中也可以自动拆箱(unboxing),也就是将对象中的基本数据类型信息自动取出.

/*例如:*/  Integer m = 10;

          int n =m ;
//相当于 n = m.intValue();
/*m变量在自动装箱为Integer的实例后,如果被赋值给一个int类型的变量
n,则自动转换为int类型在赋值,在做运算的时候也会自动拆装箱。*/
 package com.abc.tzy;

 public class AutoBoxDemo {
 public static void main(String[] args) {
     int i = 10;
     double d = 10.5;
     //把基本类型赋值给引用类型,基本类型会在编译时自动装箱
     Integer num1 = i;
     Double num2 = new Double(d);//调用这个装箱
     System.out.println(num1.intValue());
     System.out.println(num2);
     //把包装类(引用类型)复制给基本类型,会自动做拆箱
     int j = num1;
     double k = num2.doubleValue();//调用这个方法拆箱
     System.out.println(j);
     System.out.println(k);
 }
 }

自动拆装箱案例

枚举类型

1、public enum Color{

RED,BLUE,BLACK,YELLOW,GREEN

}

①enum很像特殊的class,实际上enum声明定义的类型就是一个类

②这些类都是类库中Enum类的子类(java.lang.Enum<E>),它们继承了Enum中许多有用的方法

2、枚举值都是public static final的,也就是常量,因此枚举类中的枚举值应全部大写。

3、枚举类型是class,在枚举类型中有构造器,方法和字段。但枚举构造器有很大的不同:

①构造器只是在构造枚举值的时候被调用

②构造器私有private,不允许有public构造器

4、枚举可以在switch语句中使用

 package com.abc.tzy;

 public class EnumDemo {
     public static void main(String[] args) {
         System.out.println(Color.ABC/* .toString() */);
         System.out.println("*****");
         Color[] colors = Color.values();
         for (Color color : colors) {
             System.out.println(color);
         }
         System.out.println("*****");
         System.out.println(Person1.P1);
         System.out.println("*****");
         Person1[] p = Person1.values();
         for (Person1 person1 : p) {
             System.out.println(person1);
         }
         System.out.println("*****");
         Person1 p1 = Person1.P4;
         switch (p1) {
         case P1:System.out.println(Person1.P1);break;
         case P2:System.out.println(Person1.P2);break;
         case P3:System.out.println(Person1.P3);break;
         case P4:System.out.println(Person1.P4);break;
         default:System.out.println("没有该对象");
         }

     }
 }

 // 大写常量,对象.属性-静态.
 // 当jvm去加载使用枚举类的时候,会预先创建多个枚举类型的对象供外部对象来使用
 // 加载的时候:public static final Color RED= new Color();
 enum Color {
     RED, BLUE(), ABC();
     // 枚举类型的值必须作为第一条语句出现
     /* public不让外面用-不能用 */private Color() {
         System.out.println("我是枚举");
     }
 }

 // public static final Person P1= new Person();
 enum Person1 {
     P1("张三", 14), P2("李四", 14), P3("王武", 14), P4();
     private String name;
     private int age;

     private Person1(String name, int age) {
         this.name = name;
         this.age = age;
     }

     private Person1() {

     }

     public String toString() {
         return name + "--" + age;
     }
 }

枚举

String/StringBuffer/Builder

String:

java语言中的字符串值属于String类,虽然有其他方法表示字符串(如字符数组),但java一般使用String类作为字符串的标准格式,

Java编辑器把字符串值作为String对象;

String对象一旦创建就不能被改变。如果需要进行大量的字符串修改操作,应该使用StringBuffer/Builder类或者字符数组,

最终结果可以被转换成String对象。

 package com.eduask.tzy;

 public class StringDemo {
     public static void main(String[] args) {
         // String对象的声明和操作
         String S = "我是程序员";// (常用创建方式)
         String s1 = "abcd";
         String s2 = "abcd";
         System.out.println(s1 == s2);// true
         System.out.println(s1.equals(s2));// true
         // 结论:字符串常量池里面引用
         String s = new String("我是程序员");// 不常用方式
         String s3 = new String("abcd");
         String s4 = new String("abcd");
         System.out.println(s3 == s4); // false
         System.out.println(s3.equals(s4));// true
         // 结论:在内存空间新分配一个存储空间

         // 1、String对象是不可变的
         // 2、类中每一个看来会修改String值的方法,其实都是创建了新的String对象(包含修改后的字符串内容:如拼接)
         // 3、String的只读特性带来效率优化可能
         // 4、字符串字面值储存于字符串池中,String对象优先指向该字符串池,避免发生重复的字符串事例
         // 5、系统对String的非修改处理效率很高,远远超过另外两个字符串类StringBuffer和StringBuilder(频繁修改就用后面两个类)

         /* String常用方法 */
         // ①charAt(int index) 返回指定索引处的 char 值。
         String content = "Hello,My Friend,You are my best friend";
         System.out.println(content.charAt(2));// l
         // ②compareTo(String anotherString) 按字典顺序比较两个字符串。
         System.out.println(content.compareTo("hello"));// -32
         // ③concat(String str) 将指定字符串连接到此字符串的结尾。
         content = content.concat("I lied");//content = content+"I lied";
         System.out.println(content);//Hello,My Friend,You are my best friendI lied
         //④endsWith(String suffix)测试此字符串是否以指定的后缀结束。
         System.out.println(content.endsWith("lied"));//true
         //⑤startsWith(String suffix)测试此字符串是否以指定的前缀开始。
         System.out.println(content.startsWith("Hello,"));//true
         //⑥contains(CharSequence s) 当且仅当此字符串包含指定的 char 值序列时,返回 true。
         System.out.println(content.contains("My"));//true
         //⑦equals(Object anObject)  将此字符串与指定的对象比较。(案例在上面)
         //⑧equalsIgnoreCase(String anotherString) 将此 String 与另一个 String 比较,不考虑大小写。
         //⑨indexOf(int ch)返回指定字符在此字符串中第一次出现处的索引。
         // indexOf(String str, int fromIndex)返回指定子字符串在此字符串中第一次出现处的索引,从指定的索引开始。
         // lastIndexOf(String str)返回指定子字符串在此字符串中最右边出现处的索引。
         // lastIndexOf(String str, int fromIndex) 返回指定子字符串在此字符串中最后一次出现处的索引,从指定的索引开始反向搜索。
         System.out.println(content.indexOf("o"));
         System.out.println(content.lastIndexOf("o"));
         System.out.println(content.indexOf("o",5));//17
         //⑩length()  返回此字符串的长度。
         System.out.println(content.length());//44
         //⑩① replace(char oldChar, char newChar) 返回一个新的字符串,它是通过用 newChar 替换此字符串中出现的所有 oldChar 得到的。
         System.out.println(content.replace('e', 'a'));//Hallo,My Friand,You ara my bast friandI liad
         //⑩②split(String regex) 根据给定正则表达式的匹配拆分此字符串。
          String [] arr = content.split(" ");
          System.out.println(arr.length);
          for (String string : arr) {
             System.out.print(string+"*");//Hello,My*Friend,You*are*my*best*friendI*lied*
         }
          System.out.println();
         //⑩③substring(int beginIndex)  返回一个新的字符串,它是此字符串的一个子字符串。
         //    substring(int beginIndex, int endIndex) 返回一个新字符串,它是此字符串的一个子字符串。
          System.out.println(content.substring(5));//,My Friend,You are my best friendI lied
          System.out.println(content.substring(5, 10));//,My F
         //⑩④toLowerCase() 使用默认语言环境的规则将此 String 中的所有字符都转换为小写。
         // toUpperCase()  使用默认语言环境的规则将此 String 中的所有字符都转换为大写。
          System.out.println(content.toLowerCase());//hello,my friend,you are my best friendi lied
          System.out.println(content.toUpperCase());//HELLO,MY FRIEND,YOU ARE MY BEST FRIENDI LIED
         //⑩⑤trim()    返回字符串的副本,忽略前导空白和尾部空白。
          System.out.println("   abc     ");//   abc     (有前后空格)
          System.out.println("   abc     ".trim());//abc(成功去掉前后空格)

     }
 }

 String说明及常用方法

String常用

StringBuffer:(动态字符串)

StringBuffer 线程安全的可变字符序列。

一个类似于String的字符串缓冲区(字符数组),通过某些方法调用可以改变该序列的长度和内容。

每个字符串缓冲区都有一定的容量。只要字符串缓冲区所包含字符序列的长度没有超出此容量,就无需分配新的内部缓冲区数组。

如果内部缓冲区溢出,则此容量自动增大。

StringBuilder:

从JDK5爱是,为StringBuffer类补充了一个单个线程使用的等价类,即StringBuilder.

与StingBuffer相比,通常应该优先使用StringBuilder类,因为它支持所有相同操作,但由于它不执行同步(不敲门-线程不安全),所以速度更快。

 package com.abc.tzy;

 public class StringBuilderDemo {
 public static void main(String[] args) {
     //StringBuilder sb = "abd";//无此种声明方法
     //StringBuilder sb1 = new StringBuilder();//默认16个字符大小的容量
     //StringBuilder sb2 = new StringBuilder(100);//初始化容量大小的字符串
     //StringBuilder sb3 = new StringBuilder("abc");//前三个字符就是abc
     StringBuilder sb = new StringBuilder();
     sb.append("hello");
     sb.append(1);
     sb.append(1.5);
     sb.append(true);
     System.out.println(sb.length());//长度     13
     System.out.println(sb.capacity());//容量         16
     sb.insert(5, " world ");//插入
     System.out.println(sb.toString());//打印字符串hello world 11.5true
     System.out.println(sb.length());
     System.out.println(sb.capacity());
     sb.replace(5,7,"el");//替换从index5开始替换7-5个元素为el
     System.out.println(sb.toString());//helloelorld 11.5true
     sb.replace(5,10,"el");
     System.out.println(sb.toString());//helloeld 11.5true
     System.out.println(sb.indexOf("el"));//首次出现的下标    1
     System.out.println(sb.reverse());//反转    eurt5.11 dleolleh

 }
 }

StringBuilder和StringBuffer公用的常用方法

 package com.abc.tzy;

 import java.util.Arrays;

 public class MyStringBuilderDemo {
 public static void main(String[] args) {
     MyStringBuilder msb = new MyStringBuilder();
     msb.append("hello").append(",java").append("1234567");
     System.out.println("字符个数"+msb.length());
     System.out.println("容量大小"+msb.capacity());
     System.out.println("输出字符串"+msb.toString());
 }
 }
 /*答案:
 字符个数17
 容量大小34
 输出字符串hello,java1234567
 */

 class MyStringBuilder{
     private char [] value;//字符数组
     private int count = 0;//字符数组中存放字符的个数
     public MyStringBuilder(){
         value= new char[16];
     }
     public MyStringBuilder(int capacity){
         value= new char[capacity];
     }
     public MyStringBuilder(String str){
         value= new char[str.length()+16];
     }
     //得到字符数组中的字符个数
     public int length(){
         return count;
     }
     //返回容器的容量大小
     public int capacity(){
         return value.length;
     }
     //实现字符串的添加
     public MyStringBuilder append(String str){
         int len = str.length();//获取要添加的字符串的长度
         //确保字符数组能放进去所添加的字符串
         ensureCapacity(count+len);
         //把要添加的字符串追加到新的指定数组的指定位置后面
         str.getChars(0, len, value, count);
         count+=len;//元素的个数增加了
         return this;
     }
     private void ensureCapacity(int capacity){
         //数据超出容量大小
         if(capacity>value.length){
             int newCapacity = value.length*2+2;//新字符数组大小
             value = Arrays.copyOf(value, newCapacity);
         }
     }
     //把字符数组转换为字符串显示
     public String toString(){
         return new String(value,0,count);
     }
 }

自己创建的StringBuilder

常用的一些类

Date日期类、simpleDateFormat日期格式类

Date表示特定的时间,精确到毫秒

构造方法:

publicDate()

public Date(long date)

常用方法:

见案例

DateFormat是日期/时间格式化抽象类,

它以与语言无关的方式格式化并分析

日期或时间。

日期/时间格式化子类(如SimpleDateFormat)

允许进行格式化(也就是日期》文本)、

分析(文本》日期)

构造方法:

public SimpleDateFormat()

public SimpleDateFormat(String pattern)

常用方法:

public final String format(Date date)

public Date parse(String source)

 package com.abc.tzy;

 import java.text.DateFormat;
 import java.text.ParseException;
 import java.text.SimpleDateFormat;
 import java.util.Date;
 import java.util.Locale;

 public class DateDemo {
 public static void main(String[] args) {
     //Date类常用方法
     //toString() 把此 Date 对象转换为以下形式的 String: dow mon dd hh:mm:ss zzz yyyy
     //其中: dow 是一周中的某一天 (Sun, Mon, Tue, Wed, Thu, Fri, Sat)。
     //getTime() 返回自 1970 年 1 月 1 日 00:00:00 GMT 以来此 Date 对象表示的毫秒数。
     //setTime(long time) 设置此 Date 对象,以表示 1970 年 1 月 1 日 00:00:00 GMT 以后 time 毫秒的时间点。

     Date date = new Date();
     System.out.println(date);
     //Fri Oct 06 19:42:01 CST 2017
     //星期五   十月  6号    时间           中国标准    2017年
     System.out.println(date.getTime());
     date.setTime(1507290231111L);//设置时间
     System.out.println(date);//Fri Oct 06 19:43:51 CST 2017
     //通过日期格式化类来让日期以指定方式输出 DateFormat类
     //DateFormat类 常用方法
     //getDateInstance()  获取日期格式器,该格式器具有默认语言环境的默认格式化风格。返回static DateFormat
     //getDateTimeInstance(int dateStyle, int timeStyle) 获取日期/时间格式器,该格式器具有默认语言环境的给定日期和时间格式化风格。
     //getDateTimeInstance()  获取日期/时间格式器,该格式器具有默认语言环境的默认格式化风格。返回static DateFormat
     //format(Date date, StringBuffer toAppendTo, FieldPosition fieldPosition) 将一个 Date 格式化为日期/时间字符串。返回abstract  StringBuffer
     //getDateTimeInstance(int dateStyle, int timeStyle, Locale aLocale)  获取日期/时间格式器,该格式器具有给定语言环境的给定格式化风格。
     DateFormat df1 = null;
     DateFormat df2 = null;
     DateFormat df3 = null;
     DateFormat df4 = null;
     df1 = DateFormat.getDateInstance();
     df2 = DateFormat.getDateTimeInstance();
     System.out.println("Date"+df1.format(date));//Date2017-10-6
     System.out.println("DateTime"+df2.format(date));//DateTime2017-10-6 19:43:51
     df3 = DateFormat.getDateInstance(DateFormat.FULL, new Locale("zh","CN"));
     System.out.println("Date"+df3.format(date));//Date2017年10月6日 星期五
     df4 = DateFormat.getDateTimeInstance(DateFormat.FULL, DateFormat.FULL, new Locale("zh","CN"));
     System.out.println("Date"+df4.format(date));//Date2017年10月6日 星期五 下午07时43分51秒 CST

     //自己设定日期格式SimpleDateFormat();
     //parse(String text, ParsePosition pos) 解析字符串的文本,生成 Date。
     String strDate = "2010年10月19日 10:11:30.345毫秒";
     Date d = null;
     SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss.SSS毫秒");
     SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss.SSS毫秒");
     try {
         d=sdf1.parse(strDate);//把日期字符串中的日期部分抽取出来生成一个Date对象
     } catch (ParseException e) {
         e.printStackTrace();
     }
     System.out.println(d);//Tue Oct 19 10:11:30 CST 2010
     System.out.println(sdf2.format(d));//让日期以指定模版格式格式化输出为字符串。
     //2010年10月19日 10:11:30.345毫秒
 }
 }

Date-DateFormat-SimpleDateFormat案例

Calender日历类

Calendar类是一个抽象类,为特定瞬间与一组诸如

YEAR/MONTH/DAY_OF_MONTH/HOUR等日历

字段之间的转换提供了一些方法,并为操作日历字段

(例如获得下星期的日期)提供了一些方法。瞬间

可用毫秒值来表示,它是距历元(即格林威治

标准时间1970年1月1日的00:00:00.000)的偏移量

与其他语言环境敏感类一样,Calendar提供了一个类

方法getInstance,以获得此类型的一个通用的对象。

Calendar的getInstance方法返回一个Calendar对象,

其日历字段已由当前日期和时间初始化。

 package com.abc.tzy;

 import java.util.Calendar;

 public class CalendarDemo {
 public static void main(String[] args) {
     //getInstance() 使用默认时区和语言环境获得一个日历。返回 Calendar
     Calendar c = Calendar.getInstance();
     System.out.println(c);
     /*java.util.GregorianCalendar[time=15072970758
      * 44,areFieldsSet=true,areAllFieldsSet=true,
      * lenient=true,zone=sun.util.calendar.ZoneInfo
      * [id="Asia/Shanghai",offset=28800000,
      * dstSavings=0,useDaylight=false,transitions=
      * 19,lastRule=null],firstDayOfWeek=1,
      * minimalDaysInFirstWeek=1,ERA=1,YEAR=2017,
      * MONTH=9,WEEK_OF_YEAR=40,WEEK_OF_MONTH=1,
      * DAY_OF_MONTH=6,DAY_OF_YEAR=279,DAY_OF_WEEK=6,
      * DAY_OF_WEEK_IN_MONTH=1,AM_PM=1,HOUR=9,
      * HOUR_OF_DAY=21,MINUTE=37,SECOND=55,
      * MILLISECOND=844,ZONE_OFFSET=28800000,
      * DST_OFFSET=0]
     */
     System.out.println(c.get(Calendar.YEAR));
     System.out.println(c.get(Calendar.MONTH)+1);
     System.out.println(c.get(Calendar.DATE));
     System.out.println(c.get(Calendar.HOUR_OF_DAY));
     System.out.println(c.get(Calendar.MINUTE));
     System.out.println(c.get(Calendar.SECOND));
     c.set(Calendar.YEAR, 2013);
     System.out.println(c.get(Calendar.YEAR));
     System.out.println(c.getTimeInMillis());

 /*答案:
 2017
 10
 6
 21
 46
 1
 2013
 1381067161038
 */
 }
 }

Calendar

Math数学工具类

Math类包含用于执行基本数学运算的方法,如绝对值、对数、平方根和三角函数。

它是一个final类,其中定义的都是一些常量和静态方法。

 package com.abc.tzy;

 public class MathRandomDemo {
 public static void main(String[] args) {
 /*
     Math.abs(参数) 返回绝对值 *
     Math.ceil(参数)向上取整
     Math.floor(参数) 向下取整
     Math.nextAfter(21.2, 22.5) 返回第一个参数和第二个参数之间与第一个参数相邻的浮点数
     Math.pow(2, 4) 返回2的4次方的值 *
     Math.random()  返回带正号的 double 值,该值大于等于 0.0 且小于 1.0  ****
     Math.round(25.5)  四舍五入 返回值为long型或int型 *
     Math.sqrt(16) 开正平方根 *
     Math.max(a,b) 两个数中间取最大的那个数   *
     Math.min(a,b) 两个数中间取最大的那个数     *
 */
     System.out.println(Math.floor(10.55));//10.0
     System.out.println(Math.floor(-10.55));//-11.0
     System.out.println(Math.ceil(10.55));//11.0
     System.out.println(Math.ceil(-10.55));//-10.0
     System.out.println(Math.pow(2,3));//8.0
     System.out.println(Math.round(10.6));
     System.out.println(Math.round(10.4));
     System.out.println(Math.random()*10);//2.0900889016045596
 }
 }

Math类

Random随机数类

Java中,有三种产生随机数的方法

①通过System.currentTimeMillis()来获取一个当前时间毫秒数的long型的数字

②通过Math random()返回一个0-1之间的double值(【0,1))

③通过Random类来产生一个随机数,这是专业的Random工具类,功能强大

Random类中实现的随机算法是伪随机,即有规则的随机。随即时,随机算法的起

源数字称为种子数(seed),在种子数的基础上进行一定的变换,从而产生需要的

随机数字。相同种子数Random对象,相同次数生成的随机数字相同.

两个构造方法:

public Random();种子数不同

public Random(long seed);固定种子数

 package com.abc.tzy;

 import java.util.Random;

 public class RandomGenDemo {
 public static void main(String[] args) {
     System.out.println("第一次四位验证码如下:\n"+RandomGen.codeGen());
     System.out.println("第二次四位验证码如下:\r"+RandomGen.codeGen());
     System.out.println("第三次四位验证码如下:\n"+RandomGen.codeGen());

 }
 }
 /*
 第一次四位验证码如下:
 UYFR
 第二次四位验证码如下:
 Q0ZF
 第三次四位验证码如下:
 WSJL
 */

 class RandomGen{
     //生成四位不重复的验证码
     public static String codeGen(){
         char[] codeSequence={'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z','0','1','2','3','4','5','6','7','8','9'};
         Random random = new Random();
         StringBuilder sb = new StringBuilder();//动态字符串
         int count = 0;
         while(true){
 //            下标
             int index=random.nextInt(codeSequence.length);
             char c = codeSequence[index];
             //假设取出来的字符在动态字符串中不存在,代表不重复
             if(sb.indexOf(c+"")==-1){
                 sb.append(c);//追加到动态字符串中
                 count++;
                 if(count==4){
                     break;
                 }
             }
         }
         return sb.toString();
     }
 }

四位无重复验证码

 package com.abc.tzy;

 import java.util.Random;

 public class MathRandomDemo {
     public static void main(String[] args) {
         Random random1 = new Random();
         Random random2 = new Random(10);
         Random random3 = new Random(System.currentTimeMillis());

         System.out.println(random1.nextInt());
         System.out.println(random2.nextInt());
         System.out.println(random3.nextInt());
         System.out.println(random1.nextInt(5));
         System.out.println(random1.nextBoolean());
         System.out.println(random1.nextFloat());
         System.out.println(random1.nextDouble());

         /*第一次运行结果                    第二次运行结果                第三次运行结果
         -1318050151                    -1298124408                1110696500
         -1157793070                    -1157793070                -1157793070
         1134666820                    555078446                598447802
         4                             1                        4
         true                        false                    false
         0.94795996                    0.0708338                0.26766557
         0.9270111740405302            0.569728290291566        0.38472382086060974
         */
     }
 }

Random类

异常概念

  • 什么是异常?

所谓异常就是指在程序运行的过程中发生的一些不正常事件。(如:除0溢出,数组下标越界,所要读取的文件不存在)。

  • 异常导致的后果?

Java程序的执行过程中如果出现异常事件,可以生成一个异常类对象,该对象封装了异常事件的信息,并将其被提交给java运行时系统,这个过程称为抛出异常,不处理的话

会直接导致程序直接中断。

  • 如何防止程序中断?

设计良好地程序应该在程序异常发生时提供处理这些异常的方法,使得程序不会因为异常的发生而阻断或产生不可预见的结果。

Java的异常是通过两种机制来处理的

捕获:try-catch-finally     try:监控区域,执行可能产生异常的代码   catch:捕获、处理异常    finally:善后处理,无论是否发生异常,代码总能执行

抛出:throw,throws    throw:手动抛出异常(抛出异常)    throws:声明方法可能要抛出的异常(声明异常)

try-catch-finally

try{}语句块中放的是要检测的java代码,可能有会抛出异常,也可能会正常执行。

catch(异常类型){}块是当Java运行时系统接收到try块中所抛出异常对象时,

会寻找能处理这一异常catch块来进行处理(可以有多个catch块).

finally{}不管系统有没有抛出异常都会去执行,一般用来释放资源。除了在

之前执行了System.exit(0);(退出程序)

 package com.abc.tzy;

 import java.util.InputMismatchException;
 import java.util.Scanner;

 public class ExceptionDemo {
     public static void main(String[] args) {
         System.out.println("请输入一个数字");
         Scanner input = new Scanner(System.in);
         double res = 0;
         try {
             // return; 加了return finally也会执行
             // System.exit(0);退出程序 finally不会执行(只有这种情况才不会执行)
             int number = input.nextInt();
             res = 10 / number;
         } /*
              * catch (InputMismatchException e) {
              * System.out.println(e.getMessage());// 错误信息描述
              * e.printStackTrace();// 打印堆栈错误信息 } catch (ArithmeticException e) {
              * System.out.println(e.getMessage());// 错误信息描述
              * e.printStackTrace();// 打印堆栈错误信息 }
              */catch (Exception e) {
             System.out.println(e.getMessage());// 错误信息描述
             e.printStackTrace();// 打印堆栈错误信息
         } finally {
             // 释放资源,比如关闭打开的文件,删除临时文件等。
             System.out.println("不管怎么样都打印");
         }
         System.out.println("结果为:" + (Math.round(res) + ""));

         // testTryFinally(null);
         testTryFinally("hello");
     }

     // try可以只和finally或者catch使用(单独)
     public static void testTryFinally(String name) {
         try {
             System.out.println(name.length());
         } finally {
             System.out.println("end");
         }
     }
 }
 // java.util.InputMismatchException输入小数
 // java.lang.ArithmeticException 输入0
 // java.lang.NullPointerException 参数传null

try-catch-finally

 throw和throws

throw用于手动抛出异常。作为程序员可以在任意位置手动抛出异常。

throws用于在方法上标识要暴露的异常。抛出的异常交由调用者处理。

两者区别:

①throw用在方法内,后面跟上要抛出的异常对象

②throws修饰在方法上,告诉调用者此方法可能会抛出异常,后面跟

上可能要抛出的异常类名

 package com.abc.tzy;

 public class ExceptionDemo1 {
     public static void main(String[] args) {
         Bar bar = new Bar();
         try {
             bar.enter(15);
         } catch (IllegalAccessError e) {
             System.out.println("错误信息:" + e.getMessage());
         }
         System.out.println("看看打印不");
     }
 }

 class Bar {
     public void enter(int age) /* throws IllegalAccessError写在这里主要是为了告诉调用程序员该方法可能会抛出异常 */ {
         // 一般throw和 throws一起使用。好习惯
         if (age < 18) {
             // 受查异常(必须捕获,不然编译不通过),非受查异常可以不捕获
             throw new IllegalAccessError("年龄不合格");
             // throw new Exception;//受查异常:不捕获就编译不通过.
         } else {
             System.out.println("欢迎光临");
         }
     }
 }
 // 出现这个错一般是因为访问权限错误,好好看看public,protected和private修饰符
 // IllegalAccessError这里是自己创建的非法异常

throw-throws

自定义异常:

常见异常:

RuntimeException,IOException,SQLException,ClassNotFoundException

InputMismatchException,ArithmeticException,NullPointerException,

IndexOutOfException

自定义异常:

  • Java提供的异常体系不可能预见所有希望加以报告的错误
  • 自定义异常必须从已有的异常类继承
  • 建立新的异常类型最简单的方法就是让编译器产生默认构造方法
  • 对异常来说,最重要的部分就是它的类名
  • 可以为异常类定义一个接收字符串参数的构造方法,字符串参数描述异常信息
 package com.abc.tzy;

 public class ExceptionDemo2 {
     public static void main(String[] args) {
         Bar1 bar = new Bar1();
             try {
                 bar.enter(15);
             } catch (AgeLessThanEighteenException e) {
                 System.out.println("错误信息:"+e.getMessage());
             }

         System.out.println("看看打印不");
     }
 }
 //自定义了一个异常类
 class AgeLessThanEighteenException extends Exception{
     private String message;//描述异常信息
     public AgeLessThanEighteenException(String message){
         this.message=message;
     }
     public String getMessage(){
         return message;
     }
 }

 class Bar1 {
     public void enter(int age) throws AgeLessThanEighteenException {
         if (age < 18) {
             throw new AgeLessThanEighteenException("年龄不合格");
         } else {
             System.out.println("欢迎光临");
         }
     }
 }

自定义异常

 package com.abc.tzy;

 import java.util.Random;

 public class ExceptionTest {
 public static void main(String[] args) {
     for (int i = 0; i < 10; i++) {
     Worker w = new Worker();
     Doctor d = new Doctor();
     try {
         w.work();
     } catch (SickException e) {
         d.cure(w);
         if(w.getStatus().equals("健康")){
             System.out.println("恭喜你");
         }else{
             System.out.println("我尽力了");
         }
     }finally{
         System.out.println("欢迎下次来本医院就诊");
     }
     }
 }
 }

 class Worker{
     private String status;//状态

     public String getStatus() {
         return status;
     }
     public void setStatus(String status) {
         this.status = status;
     }
     public void work() throws SickException{
         Random r = new Random();
         int rad = r.nextInt(3)+1;
         if(rad==1){
             //抛出自定义异常对象
             throw new SickException("我有病了");
         }else{
             System.out.println("身体健康不用治疗");
         }
     }
 }
 class SickException extends Exception{
     private String message;

     public SickException(String message) {
         super();
         this.message = message;
     }
     public String getMessage(String message){
         return message;
     }
 }
 class Doctor{
     public void cure(Worker worker){
         Random r = new Random();
         int rad = r.nextInt(2)+1;
         if(rad==1){
             worker.setStatus("健康");
         }else{
             worker.setStatus("死了");
         }
     }
 }

工作者医生案例

泛型

泛型简介:

  1. 泛型是JDK1.5引入的新特性,也是最重要的一个特性。
  2. 泛型可以在编译的时候检查类型安全,并且所有的强制转换都是自动和隐式的。
  3. 泛型的原理就是“类型的参数化”,即把类型看作参数。也就是说把所要操作的数据类型看作参数,就像方法的形式参数是运行时传递的值的占位符一样。
  4. 简单的说,类型变量扮演的角色就如同一个参数,它提供给编译器用来类型检查的信息。
  5. 泛型可以提高代码的扩展性和重用性。
  6. 总结:所谓泛型,即通过参数化类型来实现在同一份代码上操作多种数据类型,泛型编程是一种编程范式,它利用“参数化类型”将类型抽象化,从而实现更为灵活的复用。
 package com.abcd.tzy;
 /*泛型类模版
 1、泛型类的类型参数可以是泛型类
 2、泛型类可以同时设置多个类型参数
 3、泛型类可以继承泛型类
 4、泛型类可以实现泛型接口
 */
 public class GenericDemo {
 public static void main(String[] args) {
     GenClass<String> gen1 = new GenClass<String>("超人");
     System.out.println(gen1.getData());
     GenClass<Integer> gen2 = new GenClass<Integer>(15);
     System.out.println(gen2.getData());

 }
 }

 class GenClass <T>{
     private T data;

     public GenClass(T data) {
         super();
         this.data = data;
     }

     public T getData() {
         return data;
     }

     public void setData(T data) {
         this.data = data;
     }

 }

泛型类模版

 package com.abcd.tzy;
 /*泛型类模版
 1、泛型类的类型参数可以是泛型类
 2、泛型类可以同时设置多个类型参数
 3、泛型类可以继承泛型类
 4、泛型类可以实现泛型接口
 */
 public class GenericDemo {
 public static void main(String[] args) {
     GenClass<String> gen1 = new GenClass<String>("超人");
     System.out.println(gen1.getData());//超人
     GenClass<Integer> gen2 = new GenClass<Integer>(15);
     System.out.println(gen2.getData());

     GenClass<GenClass<Student>> gen3 = new GenClass<GenClass<Student>>();
     GenClass<Student> gen4  = new GenClass<Student>();
     gen4.setData(new Student("张三"));
     gen3.setData(gen4);
     System.out.println(gen3.getData().getData());//我是张三
     System.out.println(gen4.getData());//我是张三

     GenClass2<String,Integer> gen5 = new GenClass2<String,Integer>("李四",15);
     System.out.println("data1:"+gen5.getData1()+"\tdata2:"+gen5.getData2());//data1:李四    data2:15

 }
 }

 class GenClass2<T1,T2>{
     private T1 data1;
     private T2 data2;
     public GenClass2(T1 data1, T2 data2) {
         super();
         this.data1 = data1;
         this.data2 = data2;
     }
     public T1 getData1() {
         return data1;
     }

     public T2 getData2() {
         return data2;
     }
 }

 //创建一个泛型类
 class GenClass <T>{
     private T data;

     public GenClass() {
         super();
     }

     public GenClass(T data) {
         super();
         this.data = data;
     }

     public T getData() {
         return data;
     }

     public void setData(T data) {
         this.data = data;
     }
 }

 class Student{
     private String name;

     public Student(String name) {
         super();
         this.name = name;
     }
     public String getName() {
         return name;
     }
     public void setName(String name) {
         this.name = name;
     }
     @Override
     public String toString() {
         return "我是" + name ;
     }

 }

泛型类案例

 package com.abcd.tzy;

 public class GenericDemo1 {
     public static void main(String[] args) {
         SubClass<String, Integer> sub = new SubClass<String, Integer>("王五", 20);
         System.out.println(sub.show1());// 王五
         sub.show2(100);// 100 20
     }
 }

 class SuperClass<T1> {
     private T1 var1;

     public SuperClass(T1 var1) {
         super();
         this.var1 = var1;
     }

     public T1 show1() {
         return var1;
     }
 }

 interface IInfo<T2> {
     public void show2(T2 var2);
 }

 class SubClass<T1, T2> extends SuperClass<T1> implements IInfo<T2> {
     private T2 var2;

     public SubClass(T1 var1, T2 var2) {
         super(var1);
         this.var2 = var2;
     }

     public T1 show1() {
         return super.show1();

     }

     @Override
     public void show2(T2 var2) {
         System.out.print(var2 + "\t");
         System.out.println(this.var2);
         // System.out.println(var2+this.var2);反映会把类型变成Object类型,固不能相加
     }

 }

泛型继承和实现

限制泛型可用类型:

1、在定义泛型类别时,默认在实例化泛型类的时候可以使用任何类型,但如果想要限制

使用泛型类型时,只能用某个特定类型或者是其子类型才能实例化该类型时,可以在

定义类型时,使用extends关键字指定这个类型必须是继承某个类,或者实现某个接口

2、当没有指定泛型继承的类型和接口时,默认使用extends Object,所以默认

情况下任何类型都可以作为参数传入.

 package com.abcd.tzy;

 public class GenericDemo2 {
     public static void main(String[] args) {
         GenericClass<Dog> dogClass = new GenericClass<Dog>();
         dogClass.setObj(new Dog());
         dogClass.getObj().eat();//啃骨头
         GenericClass1<Cat> catClass = new GenericClass1<Cat>();
         catClass.setObj(new Cat());
         catClass.getObj().eat();//吃鱼肉
         //GenericClass<String> catClass = new GenericClass<String>();
         //Type mismatch: cannot convert from GenericClass<Cat> to GenericClass<String>

     }
 }
 //泛型类所接收的参数做了限制,只能接收Animal类型或者Animal的子类类型
 class GenericClass<T extends Animal>{//泛型不能实现接口,只能继承接口(接口的实例子类),也不能多继承
     private T obj;

     public T getObj() {
         return obj;
     }

     public void setObj(T obj) {
         this.obj = obj;
     }

 }

 abstract class Animal {
     public abstract void eat();
 }

 class Dog extends Animal {

     @Override
     public void eat() {
         System.out.println("啃骨头");
     }

 }

 class Cat implements Animal1 {
     public void eat() {
         System.out.println("吃鱼肉");
     }
 }

 interface Animal1{
     public void eat();
 }

 class GenericClass1<T extends Animal1>{//泛型不能实现接口,只能继承接口(接口的实例子类),也不能多继承。Animal1是接口
     private T obj;

     public T getObj() {
         return obj;
     }

     public void setObj(T obj) {
         this.obj = obj;
     }

 }

限制泛型可用类型

泛型通配声明:

同一泛型类,如果实例化时给定的实际类型不同,则这些实例的类型是不兼容的,不能相互赋值。(包括Object也不兼容);

泛型类实例之间的不兼容性会带来使用的不便。我们可以使用泛型通配符(?)声明泛型类的变量就可以解决这个问题。

泛型通配的方式:

"?"代表任意一个类型

Generic<Boolean>f1 = new Generic<Boolean>();

Generic<?>f=f1;

  和限制泛型的上限相似,同样可以使用extends关键字限定通配符匹配类型的上限(上边界通配符):

    Generic<Dog> f1 = new Generic<Dog>();

    Generic<? extends Animal> f = f1;

  还可以使用super关键词将通配符匹配类型限定为某个类型及其父类型(下边界通配符):

    Generic<Animal> f1 = new Generic<Animal>();

    Generic<? super Dog> f =f1;

 package com.abcd.tzy;

 public class GenericDemo2 {
     public static void main(String[] args) {
         GenericClass1<Dog> dogClass = new GenericClass1<Dog>();
         dogClass.setObj(new Dog());
         dogClass.getObj().eat();//啃骨头
         GenericClass1<Cat> catClass = new GenericClass1<Cat>();
         catClass.setObj(new Cat());
         catClass.getObj().eat();//吃鱼肉

         //dogClass=catClass;
         //cannot convert from GenericClass1<Cat> to GenericClass1<Dog>
         GenericClass1<String> stringClass = new GenericClass1<String>();
         stringClass.setObj("ABC");
         //无限定通配符的使用
         GenericClass1<?> gClass =null;
         gClass=dogClass;
         ((Dog)gClass.getObj()).eat();//gClass是Object类型
         gClass=catClass;
         ((Cat)gClass.getObj()).eat();
         gClass=stringClass;
         System.out.println(((String)gClass.getObj()));

         //上边界限定通配符
         GenericClass1<? extends Animal1> subclass =null;
         subclass=dogClass;
         subclass.getObj().eat();//啃骨头  //Animal1 a = dog
         subclass=catClass;
         subclass.getObj().eat();//吃鱼肉

         //下边界限定通配符
         GenericClass1<? super Dog> sClass =null;
         GenericClass1<Animal1> anClass = new GenericClass1<Animal1>();
 //        sClass=catClass;//不可以
         sClass=dogClass;
         System.out.println(sClass.getObj().getClass());//class com.abcd.tzy.Dog
         anClass.setObj(new Animal1() {
             @Override
             public void eat() {
                 System.out.println("我是动物接口匿名类");
             }
         });
         sClass=anClass;
         System.out.println(sClass.getObj().getClass());//class com.abcd.tzy.GenericDemo2$1
     }
 }

 class GenericClass1<T> {// 泛型不能实现接口,只能继承接口(接口的实例子类),也不能多继承。Animal1是接口
     private T obj;

     public T getObj() {
         return obj;
     }

     public void setObj(T obj) {
         this.obj = obj;
     }

 }

 class Dog implements Animal1 {

     @Override
     public void eat() {
         System.out.println("啃骨头");
     }

 }

 class Cat implements Animal1 {
     public void eat() {
         System.out.println("吃鱼肉");
     }
 }

 interface Animal1 {
     public void eat();
 }

泛型通配的方式

 package com.abcd.tzy;

 import java.util.Arrays;

 //要求自定义一个容器,此容器可以存放指定类型的数据。通过泛型来实现
 public class GenericDemo3 {
 public static void main(String[] args) {
     IContainer<String> list = new ArrayList<String>();
     for (int i = 0; i < 5; i++) {
         list.add("data"+(i+1));
     }
     for (int i = 0; i < list.size(); i++) {
         System.out.println(list.get(i));
     }
 }
 }
 //data1
 //data2
 //data3
 //data4
 //data5

 interface IContainer<T>{
     public void add(T obj);//给容器添加数据
     public T get(int index);//获取指定下标位置处的元素内容
     public int size();//返回容器中元素的的个数
 }

 class ArrayList<T> implements IContainer<T>{
 //    private T[] data = new T[10];错误,不能创建泛型数组
     private Object[] arrays = null;
     private int size = 0;//记录容器中元素的个数s
     public ArrayList() {
     super();
     this.arrays = new Object[10];//初始大小为10
 }
     public ArrayList(int capacity) {
     super();
     this.arrays = new Object[capacity];//初始大小为capacity
 }
     @Override
     public void add(Object obj) {
         //判断元素的个数是否已经超过了容器的大小,超过了应扩容
         ensureCapacity(size+1);
         arrays[size++]=obj;//先赋值后运算
     }
 private void ensureCapacity(int capacity){
     if(capacity>arrays.length){
         int oldCapacity = arrays.length;//获取原有数组容量的大小
         int newCapacity = oldCapacity+(oldCapacity>>1);//扩容为原有1.5倍
         arrays= Arrays.copyOf(arrays, newCapacity);//把原有数组数据拷贝到新数组中
     }
 }

     @Override
     @SuppressWarnings("unchecked")
     public T get(int index) {
         return (T)arrays[index];
     }

     @Override
     public int size() {
         return size;
     }

 }

自定义可以存放指定数据的容器

 Java集合框架

集合框架:

  所谓的框架就是一个类库的集合。集合框架就是一个用来表示和操作集合的统一的架构,它包含了实现集合的接口与类。

  集合框架中不同的集合类有各自不同的数据结构,所以在使用中要根据应用的性能要求来选择不同的集合类。

  集合类存放在java.util包中。

JavaSE高级1

Iterable接口和迭代器

Iterable接口

  实现该接口允许对象成为foreach“”语句的目标,即该集合对象允许迭代。

  类集接口Collection是Iterable的子接口,所以所有类集对象可以迭代访问,而映射Map不行。

  方法:    Iterato<T> iterator()     功能:返回一个在一组T类型的元素上进行迭代的迭代器。

迭代期是实现了Iterator/ListIterator接口的类的对象,可以通过遍历类集,访问其中的每个元素。

ListIterator扩展了父接口Iterator,允许双向遍历集合,并可以修改和删除元素

Collection接口

Collection 层次结构 中的根接口。Collection 表示一组对象,这些对象也称为 collection 的元素。
一些 collection 允许有重复的元素,而另一些则不允许。
一些 collection 是有序的,而另一些则是无序的。
JDK 不提供此接口的任何直接 实现:它提供更具体的子接口(如 Set 和 List)实现。
此接口通常用来传递 collection,并在需要最大普遍性的地方操作这些 collection。

List、Set、Map接口

List接口扩展了Collection,特点:有序且可重复的

Set接口扩展了Collection,特点:无序且不可重复

映射(map)是一个存储关键字/值(键值对)的对象,给定一个关键字,可

查询得到它的值,关键字和值都可以是对象。映射不是Collection的子接口。

所以它本身不能使用迭代期进行遍历.

List容器特点:

List容器是有序的Collection(也称为序列)。此接口的用户可以对List容器中每个元素的插入位置进行精确地控制。用户可以根据元素的整数索引(在列表中的位置)访问元素,

并搜索列表中的元素。List容器允许插入重复的值,包括NULL。

ArrayList及常用API

  ArrayList--动态数组

  ArrayList类扩展AbstractList并实现了List接口

  支持可随需增长的动态数组

  ArrayList构造方法:  ArrayList()          ArrayList(collection c)    ArrayList(int capacity)

除了继承的方法之外ArrayList常用方法:

 package com.abcd.tzy;

 import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.List;

 public class ArrayListDemo {
 public static void main(String[] args) {
     /*
      当我们调用无参数构造方法来构造一个ArrayList对象的时候,它会在内部分配一个初始大小为10的一个Object来型的数组
      当添加的数据容量炒锅数组大小的时候,会产生一个新的数据,新的数组大小为原来数组大小的1.5倍,接着把原数组中的数组拷贝到新数组中
      */
     List<String> nList = new ArrayList<String>();
     //boolean         add(E e) 将指定的元素添加到此列表的尾部。
     //void               add(int index, E element)  将指定的元素插入此列表中的指定位置。
     // E               set(int index, E element)   用指定的元素替代此列表中指定位置上的元素。
     // Iterator<E>  iterator() 返回以恰当顺序在此列表的元素上进行迭代的迭代器。 (此方法在其父类AbstractList<E>中)
     // int             indexOf(Object o)  返回此列表中首次出现的指定元素的索引,或如果此列表不包含元素,则返回 -1。
     // boolean        remove(Object o)  移除此列表中首次出现的指定元素(如果存在)。
     // E            remove(int index)  移除此列表中指定位置上的元素。
     // int             size()  返回此列表中的元素数。
     // boolean        contains(Object o)  如果此列表中包含指定的元素,则返回 true。
     // boolean         isEmpty() 如果此列表中没有元素,则返回 true
     // void         clear()  移除此列表中的所有元素。
     nList.add("zhangsan");
     nList.add("lisi");
     nList.add("wangwu");
     nList.add("liliu");
     nList.add(1,"jay");
     nList.add("jack");
     nList.set(0, "aaaa");
     System.out.println("使用迭代器对象统一遍历");
     Iterator<String> it=nList.iterator();
     //Iterator迭代器对象的方法
     //boolean hasNext() 如果仍有元素可以迭代,则返回 true。
     //E       next()    返回迭代的下一个元素。
     //void    remove()    从迭代器指向的 collection 中移除迭代器返回的最后一个元素(可选操作)。
     // E get(int index) 返回此列表中指定位置上的元素。
     while(it.hasNext()){
         String name = it.next();
         System.out.print(name+"   ");
         //aaaa   jay   lisi   wangwu   liliu   jack
     }
     System.out.println();
     System.out.println("增强For循环进行遍历");
     for (String str : nList) {
         System.out.print(str+"   ");
         //aaaa   jay   lisi   wangwu   liliu   jack
     }
     System.out.println();
     System.out.println("*********");
     System.out.println(nList.indexOf("lisi"));
     System.out.println(nList.remove("lisi"));//true
     System.out.println(nList.remove(0));//aaaa
     System.out.println(nList.size());
     System.out.println(nList.contains("zhangsan"));//false
     System.out.println(nList.get(0));//jay
     System.out.println(nList.isEmpty());//false
     nList.clear();
     System.out.println(nList.isEmpty());//true
 }
 }

ArrayList常用方法

 package com.abcd.tzy;

 import java.util.ArrayList;
 import java.util.List;

 public class ArrayListDemo1 {
     public static void main(String[] args) {
         List<Student> stuList = new ArrayList<Student>();
         Student s1 = new Student("zhangsan", 10);
         Student s2 = new Student("sadasd", 15);
         Student s3 = new Student("sisi", 12);
         Student s4 = new Student("lisi", 19);
         Student s5 = new Student("sf", 20);
         stuList.add(s1);
         stuList.add(s2);
         stuList.add(s3);
         stuList.add(s4);
         stuList.add(s5);
         Student s6 = new Student("sf", 20);
         System.out.println(stuList.indexOf(s6));//重写了equals因为姓名和年龄一样,判断为同一对象     4
         System.out.println(stuList.contains(s6));//true
         System.out.println(stuList.remove(s6));//true
         System.out.println(stuList.indexOf(s5));//-1
         System.out.println(stuList.size());//4
         //说明这几个方法都用到equals比较
     }
 }

 class Student {
     private String name;
     private int age;

     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 hashCode() {
         final int prime = 31;
         int result = 1;
         result = prime * result + age;
         result = prime * result + ((name == null) ? 0 : name.hashCode());
         return result;
     }

     @Override
     public boolean equals(Object obj) {
         if (this == obj)
             return true;
         if (obj == null)
             return false;
         if (getClass() != obj.getClass())
             return false;
         Student other = (Student) obj;
         if (age != other.age)
             return false;
         if (name == null) {
             if (other.name != null)
                 return false;
         } else if (!name.equals(other.name))
             return false;
         return true;
     }

 }

ArrayList原码应用

LinkedList及常用API

  LinkedList--链表

  LinkedList类扩展AbstractSequentialList并实现List接口

  LinkedList提供了一个链表数据结构

  LinkedList有两个构造方法: LinkedList()  LinkedList(collection c)

除了继承方法之外,LinkedList类还自定义了一些有用的方法用于操作和访问容器中的数据:

 package com.abcd.tzy;

 import java.util.Iterator;
 import java.util.LinkedList;

 public class LinkedListDemo {
     //LinkedList它内部封装的是双向链表数据结构
     //每个借点是一个Node对象,Node对象中封装的是你要添加的元素.
     //还有一个指向上一个Node对象的应用和指向下一个Node对象的引用
     /*
      不同的容器有不同的数据结构,不同的数据结构操作起来性能是不一样的
      连接数据结构,做插入、删除的效率比较高,但查询效率比较低(LinkedList)

       数组结构,它做查询的时候效率高,因为可以通过下标直接找到元素
       但插入和删除效率比较低,因为要做位移操作.(ArrayList)
      */
 public static void main(String[] args) {
     //boolean         add(E e) 将指定的元素添加到此列表的尾部。
     //void               add(int index, E element)  将指定的元素插入此列表中的指定位置。
     // E               set(int index, E element)   用指定的元素替代此列表中指定位置上的元素。
     // Iterator<E>  iterator() 返回以恰当顺序在此列表的元素上进行迭代的迭代器。 (此方法在其父类AbstractSequentialList<E>中)
     // E             removeFirst()  移除并返回此列表的第一个元素。
     // E             pollFirst()  获取并移除此列表的第一个元素;如果此列表为空,则返回 null。
     LinkedList<String> sList = new LinkedList<String>();
     //如果用父类的引用指向子类对象List->LinkedList  那么LinkedList自有的方法不能使用
     sList.add("zhansan");
     sList.add("lisi");
     sList.add("wangwu");
     sList.add("rose");
     sList.add("mary");
     sList.add("jack");
     sList.addFirst("aa");
     sList.addLast("bb");
     Iterator<String> it = sList.iterator();
         //Iterator迭代器对象的方法
         //boolean hasNext() 如果仍有元素可以迭代,则返回 true。
         //E       next()    返回迭代的下一个元素。
         //void    remove()    从迭代器指向的 collection 中移除迭代器返回的最后一个元素(可选操作)。
         // E get(int index) 返回此列表中指定位置上的元素。
     while(it.hasNext()){
         String name = it.next();
         System.out.print(name+"   ");
         //aa   zhansan   lisi   wangwu   rose   mary   jack   bb
     }
     System.out.println();
     for(Iterator<String> it1 = sList.iterator();it1.hasNext();){
         String name1 = it1.next();
         System.out.print(name1+"   ");
         //aa   zhansan   lisi   wangwu   rose   mary   jack   bb
     }
     System.out.println();
     for (String string : sList) {
         System.out.print(string+"   ");
         //aa   zhansan   lisi   wangwu   rose   mary   jack   bb
     }
     System.out.println();
     System.out.println(sList.removeFirst());//aa
     System.out.println(sList.size());
     System.out.println(sList.pollFirst());//zhansan
     System.out.println(sList.size());
     sList.clear();
     System.out.println(sList.pollFirst());//null

 }
 }

LinkedList常用方法

 package com.abcd.tzy;

 import java.util.Iterator;
 import java.util.LinkedList;
 //堆栈后进先出
 public class LinkedListDemo1 {
 public static void main(String[] args) {
     MyStack<String> mystack = new MyStack<String>();
     mystack.push("zhangsan");
     mystack.push("lisi");
     mystack.push("wangwu");
     mystack.push("zhaoliu");
     mystack.pop();
     mystack.pop();
     Iterator<String> it = mystack.iterator();
     while(it.hasNext()){
         System.out.print(it.next()+"  ");//lisi  zhangsan
     }
 }
 }

 class MyStack<T>{
     private LinkedList<T> data = null;
     public MyStack(){
         data=new LinkedList<T>();
     }
     //压栈的方法
     public void push(T obj){
         data.addFirst(obj);
     }
     //出栈的方法
     public T pop(){
         return data.removeFirst();
     }
     public Iterator<T> iterator(){
         return data.iterator();
     }
 }

LinkedList模拟堆栈

自建ArrayList及Iterator

 package com.tzy.iterator;

 public interface Iterator<T> {
 public boolean hasNext();//判断是否有下一个元素
 public T next();//获取下一个元素的内容
 }

interface-->Iterator

 package com.tzy.iterator;

 public interface List<T>{
 public void add(T obj);//给具体的容器添加元素
 public T get(int index);//获取指定位置上的元素
 public int size();//获取容器中的元素个数
 public Iterator<T> iterator();//获取迭代器
 }

interface-->List

 package com.tzy.iterator;

 public class ArrayList<T> implements List<T> {
 private Object [] obj =null;//声明一个Object类型的数组
 private int index;//数组的下标
 private int size;//记录数组中元素的个数

     public ArrayList() {
     super();
     obj = new Object[10];
     index=0;
     size=0;
 }

     @Override
     public void add(T obj) {
         this.obj[index++]=obj;//把数据存放到数组中
         size++;
     }

     @SuppressWarnings("unchecked")//压制警告
     @Override
     public T get(int index) {
         return (T) this.obj[index];
     }

     @Override
     public int size() {
         return size;
     }

     @Override
     public Iterator<T> iterator() {
         return new MyIterator<T>(this);
     }

 }

class-->ArrayList

 package com.tzy.iterator;

 public class MyIterator<T> implements Iterator<T> {
 private List<T> list =null;
 private int index = 0;//访问到容器中元素的当前下标

     public MyIterator(List<T> list) {
     super();
     this.list = list;
 }
 //判断是否有下一个元素
     @Override
     public boolean hasNext() {
         return index<list.size();
     }
 //取出下一个元素
     @Override
     public T next() {
         return list.get(index++);
     }

 }

class-->MyIterator

 package com.tzy.iterator;

 public class Test {
 public static void main(String[] args) {
     List<String> nameList = new ArrayList<String>();
     nameList.add("zhangsan");
     nameList.add("lisi");
     nameList.add("wangwu");
     nameList.add("aa");
     nameList.add("bb");
     Iterator<String> it = nameList.iterator();
     while(it.hasNext()){
         System.out.println(it.next());
     }
     System.out.println("********");
     for (int i = 0; i < nameList.size(); i++) {
         System.out.println(nameList.get(i));
     }
 }
 }

class-->Test

Map接口详解

  • 映射(map)是一个储存键/值对的对象。给定一个键,可查询得到它的值,键和值都是对象。
  • 键必须是唯一的,值可以重复。
  • 有些映射可以接收null键和null值,而有的不行。
  • 下面的接口支持映射:
接口 描述
Map 映射唯一关键字给值
Map.Entry 描述映射中的元素(关键字/值对)。这是Map的一个内部类
SortedMap 扩展Map以便关键字按升序保持
  • Map接口映射唯一键到值
  • 键(key)是以后用于检索值的对象。给定一个键和一个值,可以存储这个值到一个Map对象中,以后可以使用对应键检索它
  • Map接口定义的方法:(见案例)
  • Map.Entry接口代表映射项(键-值对)类型,是Map的嵌套类型(内部接口)
  • Map接口定义的entrySet()方法返回包含映射项Entry的集合(Set),集合中元素是Map.Entry类型
  • Map.Entry接口定义的方法:(见案例)

HashMap及常用API

  • HashMap类是基于哈希表的map接口的实现,并允许使用null键和null值。
  • 构造方法:HashMap()    HashMap(Map m)    HashMap(int capacity)    HashMap(int capacity,float fillRato)      fillRato最好的值是0.75  重复率和运行是最好的
  • HashMap实现Map并扩展AbstractMap,本身并没有增加任何新的方法
  • 散列映射不保证它的元素的顺序,元素加入散列映射的顺序并不一定是它们被迭代读出的顺序
 package com.abc.tzy;

 import java.util.Collection;
 import java.util.HashMap;
 import java.util.Map.Entry;
 import java.util.Set;

 public class HashMapDemo {

     public static void main(String[] args) {
         // V             put(K key, V value) 在此映射中关联指定值与指定键。
         // Set<K>         keySet()  返回此映射中所包含的键的 Set 视图。
         //Collection<V> values() 返回此映射所包含的值的 Collection 视图。
         // V             get(Object key) 返回指定键所映射的值;如果对于该键来说,此映射不包含任何映射关系,则返回 null。
         // int             size()     返回此映射中的键-值映射关系数。
         // boolean         isEmpty()  如果此映射不包含键-值映射关系,则返回 true。
         // void         clear()   从此映射中移除所有映射关系。
         //Set<Map.Entry<K,V>> entrySet()  返回此映射所包含的映射关系的 Set 视图。
         HashMap<String,String> map = new HashMap<String,String>();
         map.put("jay", "张三");
         map.put("jay", "李四");//将上一个键一样的对象覆盖了
         map.put("rose", "玫瑰");
         map.put("mary", "李四");
         System.out.println(map);
         //{jay=李四, mary=李四, rose=玫瑰}

         Set<String> keys = map.keySet();
         for (String k : keys) {
             System.out.print(k+"___"+map.get(k)+"   ");
         }
         //jay___李四   mary___李四   rose___玫瑰
         System.out.println();

         Collection<String> values = map.values();
         for (String v : values) {
             System.out.print(v+"   ");
         }
         //李四   李四   玫瑰
         System.out.println();

         System.out.println(map.size());//3

         //当我们调用put(key,value)方法的时候,首先会把key,value封装到
         //Entry这个静态内部类对象中。把Entry对象在添加到数组中。所以我们
         //想获取map中的所有键值对,我们只要获取数组中的所有Entry对象,接下来
         //调用Entry对象中的getKey(),getValue()方法就能获取键值对。
         Set<Entry<String, String>> entrySet = map.entrySet();
         for(Entry<String, String> entry:entrySet){
             System.out.print(entry.getKey()+"***"+entry.getValue()+"  ");
         }
         //jay***李四  mary***李四  rose***玫瑰  true
         System.out.println();

         map.clear();
         System.out.println(map.isEmpty());//true
     }

 }

HashMap常用

 package com.abc.tzy;

 import java.util.HashMap;
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Set;
 //字符串出现次数计算器
 public class AccountStringDemo {
 public static void main(String[] args) {
     String [] strs = {"zhangsan","lisi","wangwu","zhangsan","liumang"};
     AccountUtil.printData(AccountUtil.account(strs));
 }
 }
 //lisi出现的次数1
 //liumang出现的次数1
 //zhangsan出现的次数2
 //wangwu出现的次数1

 class AccountUtil{
     public static Map<String,Integer> account(String[] strs){
         Map<String,Integer> data = new HashMap<String,Integer>();
         for (int i = 0; i < strs.length; i++) {
             String str = strs[i];
             if(data.get(str)==null){
                 data.put(str, 1);
             }else{
                 //取出key所对应的值+1
                 data.put(str, (data.get(str)+1));
             }
         }
         return data;
     }
     public static void printData(Map<String,Integer> data){
         Set<Entry<String, Integer>> entrySet = data.entrySet();
         for (Entry<String, Integer> entry : entrySet) {
             System.out.println(entry.getKey()+"出现的次数"+entry.getValue());
         }
     }
 }

HashMap案例

注:HashMap调用默认构造方法会产生一个底层长度为16的Entry数组。

  int hash = hash(key.hashCode()); 首先调用key的hashCode方法来得到一个整数-哈希码

  把哈希码作为参数传到hash函数中来进行运算--散列运算--得到了一个整形

  int i = indexFor(hash,table.length); 把散列值和数组的长度来进行运算,最终得到Entry对象要存放到数组的位置(下标);

  hashMap内部的结构是数组链表结构。因为不同的key有可能算出来是相同的散列值,根据散列值计算出存放到数组的下标会冲突。

哈希码的产生和使用:

  当调用对象的hashCode()方法时就会返回当前对象的哈希码值。支持此方法是为了提高哈希表的性能。

  hashCode()的常规协定:

    1、在Java应用程序执行期间,在统一对象多次调用hashCode方法时,必须一致地返回相同的整数,前提是将对象进行equals比较时所用的信息没有被修改。从

    某一应用程序的一次执行到统一应用程序的另一次执行,该整数无需保持一致。

    2、如果根据equals(Object)方法,两个对象是相等的,那么对这两个对象中的每个对象调用hashCode方法都必须生成相同的整数结果。

    注:这里说的equals(object)方法指的是Object类中未被子类重写过的equals方法。

    3、如果根据equeals(java.lang.Object)方法,两个对象不想等,那么对这两个对象中的任一对象调用hashCode方法不要求一定生成不同的整数结果。但是

    程序员应该意识到,为不相等的生成不同整数结果可以提高哈希表的性能。

 package com.abc.tzy;

 import java.util.HashMap;
 import java.util.Map;

 public class HashMapDemo1 {
 public static void main(String[] args) {
     Map<Student,String> map = new HashMap<Student,String>();
     map.put(new Student("jay", 15), "张三");
     map.put(new Student("lisi", 30), "李四");
     map.put(new Student("rose", 20), "玫瑰");
     map.put(new Student("lisi", 30), "拉拉");
     //重写hashCode和equals后名字和年龄一样会被认为是同一个对象。
     System.out.println(map);
     System.out.println(map.size());
 }
 }

 class Student{
     private String name;
     private int age;
     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 hashCode() {
         final int prime = 31;
         int result = 1;
         result = prime * result + age;
         result = prime * result + ((name == null) ? 0 : name.hashCode());
         return result;
     }
     @Override
     public boolean equals(Object obj) {
         if (this == obj)
             return true;
         if (obj == null)
             return false;
         if (getClass() != obj.getClass())
             return false;
         Student other = (Student) obj;
         if (age != other.age)
             return false;
         if (name == null) {
             if (other.name != null)
                 return false;
         } else if (!name.equals(other.name))
             return false;
         return true;
     }

 }

hashCode例

TreeMap及常用API

  TreeMap类通过使用红黑树实现Map接口

  TreeMap提供按排序顺序储存键/值对的有效数段,同时允许快速检索

  不像散列映射,树映射保证它的元素按关键字升序排序

  TreeMap构造方法: TreeMap()    TreeMap(comparator comp)     TreeMap(Map m)    TreeMap(SortedMap sm)   

  TreeMap实现SortedMap并扩展AbstractMap,它本身没有定义其他方法

 package com.abc.tzy;

 import java.util.Map.Entry;
 import java.util.Set;
 import java.util.TreeMap;

 public class TreeMapDemo {
 public static void main(String[] args) {
     // V             put(K key, V value) 在此映射中关联指定值与指定键。
     // Set<K>         keySet()  返回此映射中所包含的键的 Set 视图。
     //Collection<V> values() 返回此映射所包含的值的 Collection 视图。
     // V             get(Object key) 返回指定键所映射的值;如果对于该键来说,此映射不包含任何映射关系,则返回 null。
     // int             size()     返回此映射中的键-值映射关系数。
     // boolean         isEmpty()  如果此映射不包含键-值映射关系,则返回 true。
     // void         clear()   从此映射中移除所有映射关系。
     //Set<Map.Entry<K,V>> entrySet()  返回此映射所包含的映射关系的 Set 视图。 

     TreeMap<String,String> tmap = new TreeMap<String,String>();
     tmap.put("cack", "张三");            //               10        现在有个6往里面插入
     tmap.put("jay", "李四");            //              /  \        比10小那么和5比较
     tmap.put("arose", "玫瑰");        //             5      11    比5大那么和7比较
     tmap.put("jay", "王武");            //            / \
     tmap.put("dary", "李四");            //           3   7        比7小那么放左边
     System.out.println(tmap);        //              /
                                     //             6
     //{arose=玫瑰, cack=张三, dary=李四, jay=王武}  排序有顺序乍眼看像是abcd顺序  其实是二叉树放的(红黑树)如上:
     Set<Entry<String, String>> entrySet = tmap.entrySet();
     for (Entry<String, String> entry : entrySet) {
         System.out.print(entry.getKey()+"---"+entry.getValue()+"   ");
     }
     //arose---玫瑰   cack---张三   dary---李四   jay---王武
 }
 }

TreeMap常用

 package com.abc.tzy;

 import java.util.Comparator;
 import java.util.TreeMap;

 public class TreeMapDemo1 {
     public static void main(String[] args) {
         TreeMap<Person,String> pdata = new TreeMap<Person,String>();

         pdata.put(new Person("zhangsan", 15), "张三");
         pdata.put(new Person("lisi", 31), "李四");
         pdata.put(new Person("rose", 32), "玫瑰");
         pdata.put(new Person("zhangsan", 33), "张六");
         System.out.println(pdata);
         // java.lang.ClassCastException: com.abc.tzy.Person cannot be cast to java.lang.Comparable
         //需要实现comparable接口自然比较
         //重写排序方法后{com.abc.tzy.Person@659e0bfd=张三, com.abc.tzy.Person@2a139a55=李四, com.abc.tzy.Person@15db9742=玫瑰, com.abc.tzy.Person@6d06d69c=张三}
         TreeMap<Person1,String> pdata1 = new TreeMap<Person1,String>(new Comparator<Person1>() {
             @Override
             public int compare(Person1 o1, Person1 o2) {
                 /*if(o1.getAge()-o2.getAge()>0){
                     return 1;
                 }else if(o1.getAge()-o2.getAge()<0){
                     return -1;
                 }
                 return 0;*/
                 //按名字排序
                 //String的方法     : int     compareTo(String anotherString)  按字典顺序比较两个字符串。
                 //return o1.getName().compareTo(o2.getName());
                 //结果:{com.abc.tzy.Person1@7852e922=李四, com.abc.tzy.Person1@4e25154f=玫瑰, com.abc.tzy.Person1@70dea4e=张六}
                 //少了一个对象 因为名字一样 值被覆盖了  那么要让名字一样比较age:
                 if(o1.getName().compareTo(o2.getName())>0){
                     return 1;
                 }else if(o1.getName().compareTo(o2.getName())<0){
                     return -1;
                 }else{
                     return o1.getAge()-o2.getAge();
                 }
             }
         });
         pdata1.put(new Person1("zhangsan", 39), "张三");
         pdata1.put(new Person1("lisi", 31), "李四");
         pdata1.put(new Person1("rose", 32), "玫瑰");
         pdata1.put(new Person1("zhangsan", 33), "张六");
         System.out.println(pdata1);
         //{com.abc.tzy.Person1@7852e922=张三, com.abc.tzy.Person1@4e25154f=李四, com.abc.tzy.Person1@70dea4e=玫瑰, com.abc.tzy.Person1@5c647e05=张六}

     }

 }

 class Person implements Comparable<Person>{
     private String name;
     private int age;
     public Person(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(Person o) {
         if(this.age-o.getAge()>0){
             return 1;
         }else if(this.age-o.getAge()<0){
             return -1;
         }
         return 0;
     }

 }
 class Person1 {
     private String name;
     private int age;
     public Person1(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;
     }

 }

TreeMap->Comparator->Comparable

TreeMap的key储存引用类型数据,需要满足一定条件

  要么引用类型实现Comparable接口

  要么为该TreeMap容器提供实现Comparator接口的比较器对象

 

Set容器特点:

  Set容器是一个不包含重复元素的Collection,并且最多包含一个NULL元素,它和List容器相反,Set容器不能保证其元素的顺序。

  最常用的Set接口的实现类是HashSet和treeSet

HashSet及常用API

  HashSet扩展AbstractSet并且实现Set接口

  HashSet使用散列表(又称哈希表)进行储存---->底层封装了HashMap--->HashMap实例--->哈希表(其实就是操作HashMap的键)

  构造方法:HashSet()  HashSet(Collection c)    HashSet(int capacity)    HashSet(int capacity,float fillRatio)

  HashSet没有定义任何超过它父类和接口提供的其他方法

  散列集合没有确保其元素的顺序,因为散列处理通常不参与排序

 package com.abc.tzy;

 import java.util.HashSet;

 public class HashSetDemo {
     public static void main(String[] args) {
         // boolean  add(E e) 如果此 set 中尚未包含指定元素,则添加指定元素。
         // int         size()  返回此 set 中的元素的数量(set 的容量)。
         //boolean     isEmpty() 如果此 set 不包含任何元素,则返回 true。
       //Iterator<E> iterator()   返回对此 set 中元素进行迭代的迭代器。
         // boolean     contains(Object o) 如果此 set 包含指定元素,则返回 true。
         //boolean     remove(Object o)  如果指定元素存在于此 set 中,则将其移除。
         // void     clear()  从此 set 中移除所有元素。
         HashSet<String> data = new HashSet<String>();
         data.add("zhangsan");
         data.add("lisi");
         System.out.println(data.add("jay"));//true
         data.add("jack");
         System.out.println(data.add("jay"));//false
         System.out.println(data);//[lisi, jay, zhangsan, jack]
         HashSet<Student2> stuSet = new HashSet<Student2>();
         System.out.println(stuSet.add(new Student2("张三", 12)));
         System.out.println(stuSet.add(new Student2("李四", 20)));
         System.out.println(stuSet.add(new Student2("张三", 12)));//重写equals和hashCode就是false;
         System.out.println(stuSet.size());

     }
 }

 class Student2{
     private String name;
     private int 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;
     }
     public Student2(String name, int age) {
         super();
         this.name = name;
         this.age = age;
     }
     @Override
     public int hashCode() {
         final int prime = 31;
         int result = 1;
         result = prime * result + age;
         result = prime * result + ((name == null) ? 0 : name.hashCode());
         return result;
     }
     @Override
     public boolean equals(Object obj) {
         if (this == obj)
             return true;
         if (obj == null)
             return false;
         if (getClass() != obj.getClass())
             return false;
         Student2 other = (Student2) obj;
         if (age != other.age)
             return false;
         if (name == null) {
             if (other.name != null)
                 return false;
         } else if (!name.equals(other.name))
             return false;
         return true;
     }

 }

HashSet常用

 TreeSet及常用API

  TreeSet为使用树来进行存储的Set接口提供了一个工具,对象按升序储存,访问和检索很快

  在存储了大量的需要进行快速检索的排序信息的情况下,TreeSet是一个很好的选择

  构造方法见API

总结:TreeSet的内部操作的底层数据是TreeMap,只是我们操作的是TreeMap的Key

 package com.abc.tzy;

 import java.util.Comparator;
 import java.util.Iterator;
 import java.util.TreeSet;

 public class TreeSetDemo {
     public static void main(String[] args) {
         TreeSet<Person2> pset = new TreeSet<Person2>();
         pset.add(new Person2("chenyi", 12));
         pset.add(new Person2("taoer", 22));
         pset.add(new Person2("zhangsan", 16));
         pset.add(new Person2("lisi", 19));
         System.out.println(pset);
         //[com.abc.tzy.Person2@659e0bfd, com.abc.tzy.Person2@2a139a55, com.abc.tzy.Person2@15db9742, com.abc.tzy.Person2@6d06d69c]
         // java.lang.ClassCastException:
         //com.abc.tzy.Person2 cannot be cast to java.lang.Comparable
         Iterator<Person2> it = pset.iterator();
         while(it.hasNext()){
             Person2 p = it.next();
             System.out.println(p.getName()+"---"+p.getAge());
         }
         //chenyi---12
         //zhangsan---16
         //lisi---19
         //taoer---22
 System.out.println("************");
         TreeSet<Person3> ppset = new TreeSet<Person3>(new Comparator<Person3>() {

             @Override
             public int compare(Person3 o1, Person3 o2) {
                 if(o1.getAge()-o2.getAge()>0){
                     return 1;
                 }else if(o1.getAge()-o2.getAge()<0){
                     return -1;
                 }
                 return o1.getName().compareTo(o2.getName());
             }
         });
         ppset.add(new Person3("chenyi", 22));
         ppset.add(new Person3("taoer", 22));
         ppset.add(new Person3("zhangsan", 22));
         ppset.add(new Person3("lisi", 22));
         Iterator<Person3> it1 = ppset.iterator();
         while(it1.hasNext()){
             Person3 p = it1.next();
             System.out.println(p.getName()+"---"+p.getAge());
         }
         //chenyi---22
         //lisi---22
         //taoer---22
         //zhangsan---22

     }
 }

 class Person2 implements Comparable<Person2>{
     private String name;
     private int age;
     public Person2(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(Person2 o) {
         if(this.age-o.age>0){
             return 1;
         }else if(this.age-o.age<0){
             return -1;
         }
         return 0;
     }

 }
 class Person3 {
     private String name;
     private int age;
     public Person3(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;
     }

 }

TreeSet常用

Collections类及常用API

Collections-类集工具类,定义了若干用于类集和映射的算法,这些算法被定义为静态方法。(相当于服务数组的Arrays类)

 package com.abc.tzy;

 import java.util.List;
 import java.util.ArrayList;
 import java.util.Collections;

 public class CollectionsDemo {
 public static void main(String[] args) {
     List<String> nList = new ArrayList<String>();
     nList.add("zhangsan");
     nList.add("lisi");
     nList.add("wangwu");
     nList.add("zhaoliu");
     nList.add("jack");
     nList.add("rose");
     System.out.println("操作前");
     for (String s : nList) {
         System.out.print(s+"  ");
     }
     System.out.println();
     System.out.println("交换后");
     //swap(List<?> list, int i, int j) 在指定列表的指定位置处交换元素。
     Collections.swap(nList, 1, 2);
     for (String s : nList) {
         System.out.print(s+"  ");
     }
     System.out.println();
     System.out.println("反转后");
     //reverse(List<?> list) 反转指定列表中元素的顺序。
     Collections.reverse(nList);
     for (String s : nList) {
         System.out.print(s+"  ");
     }
     System.out.println();
     System.out.println("自然排序后");
     //sort(List<T> list)根据元素的自然顺序 对指定列表按升序进行排序。
     Collections.sort(nList);
     for (String s : nList) {
         System.out.print(s+"  ");
     }

     System.out.println();
     System.out.println("二分法查找");
     //binarySearch(List<? extends Comparable<? super T>> list, T key)  使用二分搜索法搜索指定列表,以获得指定对象。
     System.out.println(Collections.binarySearch(nList, "rose"));
     System.out.println(Collections.binarySearch(nList, "abc"));
     System.out.println();
     System.out.println("打乱顺序");
     //shuffle(List<?> list) 使用默认随机源对指定列表进行置换。每次运行都会打乱
     Collections.shuffle(nList);
     for (String s : nList) {
         System.out.print(s+"  ");
     }
     System.out.println();
     System.out.println("填充");
     //fill(List<? super T> list, T obj) 使用指定元素替换指定列表中的所有元素。
     Collections.fill(nList,"aaa");
     for (String s : nList) {
         System.out.print(s+"  ");
     }

 /*
 操作前
 zhangsan  lisi  wangwu  zhaoliu  jack  rose
 交换后
 zhangsan  wangwu  lisi  zhaoliu  jack  rose
 反转后
 rose  jack  zhaoliu  lisi  wangwu  zhangsan
 自然排序后
 jack  lisi  rose  wangwu  zhangsan  zhaoliu
 二分法查找
 2
 -1

 打乱顺序
 jack  zhaoliu  wangwu  zhangsan  lisi  rose
 填充
 aaa  aaa  aaa  aaa  aaa  aaa
 */
 }
 }

Collections常用

 package com.ab.tzy;

 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.List;

 //sort(List<T> list, Comparator<? super T> c)
 //根据指定比较器产生的顺序对指定列表进行排序。
 public class ArrayListDemo {
     public static void main(String[] args) {
         List<Person> data = new ArrayList<Person>();
         data.add(new Person("jack", 20, 10));
         data.add(new Person("rose", 10, 7));
         data.add(new Person("mary", 30, 6));
         data.add(new Person("zhang", 50, 8));
         data.add(new Person("jay", 20, 12));
         Collections.sort(data, new Comparator<Person>() {

             @Override
             public int compare(Person o1, Person o2) {
                 if (o1.getAge() - o2.getAge() > 0) {
                     return 1;
                 } else if (o1.getAge() - o2.getAge() < 0) {
                     return -1;
                 } else {
                     return o1.getName().compareTo(o2.getName());
                 }

             }

         });
         for (Person person : data) {
             System.out.println(person);
         }
         // Person [name=rose, age=10, id=7]
         // Person [name=jack, age=20, id=10]
         // Person [name=jay, age=20, id=12]
         // Person [name=mary, age=30, id=6]
         // Person [name=zhang, age=50, id=8]

     }
 }

 class Person {
     private String name;
     private int age;
     private int id;

     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 int getId() {
         return id;
     }

     public void setId(int id) {
         this.id = id;
     }

     public Person(String name, int age, int id) {
         super();
         this.name = name;
         this.age = age;
         this.id = id;
     }

     @Override
     public String toString() {
         return "Person [name=" + name + ", age=" + age + ", id=" + id + "]";
     }

 }

Collections-->ArrayList自定义排序