内部类
内部类概念:
所谓内部类(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 自定义异常:
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("死了"); } } } 工作者医生案例 |
泛型
泛型简介:
- 泛型是JDK1.5引入的新特性,也是最重要的一个特性。
- 泛型可以在编译的时候检查类型安全,并且所有的强制转换都是自动和隐式的。
- 泛型的原理就是“类型的参数化”,即把类型看作参数。也就是说把所要操作的数据类型看作参数,就像方法的形式参数是运行时传递的值的占位符一样。
- 简单的说,类型变量扮演的角色就如同一个参数,它提供给编译器用来类型检查的信息。
- 泛型可以提高代码的扩展性和重用性。
- 总结:所谓泛型,即通过参数化类型来实现在同一份代码上操作多种数据类型,泛型编程是一种编程范式,它利用“参数化类型”将类型抽象化,从而实现更为灵活的复用。
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包中。
Iterable接口和迭代器 Iterable接口 实现该接口允许对象成为foreach“”语句的目标,即该集合对象允许迭代。 类集接口Collection是Iterable的子接口,所以所有类集对象可以迭代访问,而映射Map不行。 方法: Iterato<T> iterator() 功能:返回一个在一组T类型的元素上进行迭代的迭代器。 迭代期是实现了Iterator/ListIterator接口的类的对象,可以通过遍历类集,访问其中的每个元素。 ListIterator扩展了父接口Iterator,允许双向遍历集合,并可以修改和删除元素 |
Collection接口 Collection 层次结构 中的根接口。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自定义排序