zoukankan      html  css  js  c++  java
  • Java程序设计学习笔记(二)

    ——正则表达式
        正则表达式

            ^ 匹配的开始
            $ 匹配的结束
            [] 表示匹配任意一个字符
                [asdasd]
                [a-z] 相当于 abcdefghijklmnopqestuvwxyz
            + 匹配一次到多次
            * 匹配0次到多次
            ? 匹配0次或1次
            {m,n} 匹配m到n次 最少匹配m次最多匹配n次
            {m,}  至少匹配m次
            {,n}  最多匹配n次
            {m}   匹配m次
            [123]|[abc] 或

    ——Date类
        Date类十一个较为常用的类,但是操作的日期格式会有一些不符合于个人的要求,而如果要想进一步取得一些自己需要的时间,则可
        以使用Calendar类。
        
        Date类本身使用非常简单,直接输出其实例化对象即可获取当前时间。

        java.util.Date
            getTime()
                获取从1970年1月1日到现在个毫秒值。
        java.sql.Date
            构造方法
                Date(long date)
                    long date:从1970年1月1日到指定日期的毫秒值参数,还可以使用new Date().getTime()作为参数
       


    ——Calendar类

        使用此类可以将日期精确到毫秒。
        Calendar是一个抽象类,无法直接使用,此时就要利用对象多态的概念,通过向上转型关系实例化本类对象。
        通过Calendar类取得一个完整的日期,使用其子类GregorianCalendar来创建对象。
        
        通过此类就可以非常轻松的取得一个完整的日期,但是在取得月份的时候要特别注意,需要月份+1,因为月份是从0开始计算。
        如果按照此种方式取得,则也会很麻烦,最好的做法是将Date进行一些相关的格式化操作。
        
        方法:
                add(int Calendar.YEAR, int 偏移量)
                    偏移量可以为负值。
                set(inte year,int month,int day)
                    需要注意的是month是从0开始的。

        总结:
            虽然Date类直接取出的时间格式并不是十分理想, 但是其作用依然很大。
            通过Calendar类可以取得完整的时间。



    ——DateFormat类

        位于java.text包中。

        此类是一个日期的格式化类,专门格式化日期的操作,因为java.util.Date类本身就已经包含了完整的日期,所以只需要将此日期按照
        一些好的格式格式化一下显示就好了。

        虽然DateFormat是Format的子类,但是从定义上可以发现,此类是一个抽象类,按照以往的思路,直接使用其子类实例化即可。
        但是DateFormat类本身的内部提供了可以直接为其实例化的操作。
            public static final DateFormat  getDateInstance()
                得到日期的DateFormat对象。
            public static final DateFormat getDateTimeInstance()
                得到日期时间的DateFormat对象。

        直接使用DateFormat类完成Date类的转换功能。
            public class DateDemo01 {
            public static void main(String[] args)
            {
                DateFormat df1 = null;
                DateFormat df2 = null;
     
                df1 = DateFormat.getDateInstance();
                df2 = DateFormat.getDateTimeInstance();
     
                System.out.println(df1.format(new Date()));
                System.out.println(df2.format(new Date()));
            }
        }
        通过此类可以直接将Date类的显示进行合理的格式化操作,此时采用的是默认的格式化。


    ——SimpleDateFormat类

        以指定格式输出日期和时间。
        此类的功能是完成日期的显示格式化的,例如在开发中可能会将一种日期格式转换为另外一种日期格式,如下所示:
            原始日期:    2016-3-17 23:52:15
            转换后如期:2016年3月17日23:52:25
        以上的两个日期中的数字是完全一样的,唯一不同的是日期的显示格式不同,所以要想实现这样的转换功能就必须依
        靠SimpleDateFormat类。
        
        如果想要实现转换,则必须首先准备好一个模板,通过此模板进行日期数字的提取工作。 
            格式如下:
                y:
                    表示年,因为年份是4位数字,所以使用“yyyy”来表示。
                M:
                    表示月,因为月份是2位数字,所以使用“MM”来表示。
                d:
                    表示日,因为日是2位数字,所以用“dd”来表示。
                H:
                    表示时,因为时是2位数字,所以用“HH”来表示。
                m:
                    表示分,因为分是2位数字,所以用“mm”来表示。
                s:
                    表示秒,因为秒是2位数字,所以用“mm”来表示。
                S:
                    表示毫秒,毫秒是3位数字,所以用“SSS”来表示。

            在SimpleDateFormat类使用的时候,必须注意的是在构造对象时要传入匹配的模板。
            构造方法:
                SimpleDateFormat(String pattern)
                    用给定的模式和默认语言环境的日期格式符号构造 SimpleDateFormat
                    实例化模板对象,使用模板对象来
            转换:
                public Date parse(String prase, ParsePosition pos)
                    将指定字符串转换为Date对象。
                    此时取得的是全部的时间数。
            格式化:
                public final String format(Date date)
                    将旧的日期重新格式化。
                    将时间重新格式化成字符串显示。

        public class DateDemo01 {
            public static void main(String[] args)
            {
                String strDate = "2016-3-18 00:27:12:555";
     
                //准备第一个模板,从字符串中提取出日期数字
                String pat1 = "yyyy-MM-dd HH:mm:ss:SSS";
                //准备第二个模板,将提取后的日期数字变为指定的格式
                String pat2 = "yyyy年MM月dd日 HH时mm分ss秒SSS毫秒";
     
                SimpleDateFormat sdf1 = new SimpleDateFormat(pat1);    //实例化模板
                SimpleDateFormat sdf2 = new SimpleDateFormat(pat2);    //实例化模板
     
                Date d = null;
                try {
                    d = sdf1.parse(strDate);
                    System.out.println(sdf1.format(d));
                } catch (ParseException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                System.out.println(sdf2.format(d));
            }
        }

        ------------------------------------------------------------------------------------
        输出结果:
            
            2016-03-18 00:27:12:555
            2016年03月18日 00时27分12秒555毫秒

        总结:
            1、DateFormat可以直接使用,但其本身十一个抽象类。
            2、SimpleDateFormat类是DateFormat类的子类,一般情况下来将DateFormat类很少会直接使用,而是使用SimpleDateFormat。

    ——取得当前日期
        开发中经常需要取得日期,而且每次取得日期的时候代码都会重复,所以既然是重复的代码就可以将其定义成一个类,以方便重复
        调用,但是在操作的时候有一点特别需要注意:
            如果月份是9月,则应该显示09,但是如果是09的话,则肯定会忽略掉数字0。
        1、先通过Calendar操作
            public class CalendarDemo01 {
    public static void main(String[] args)
    {
    DateTime dt = new DateTime();
    System.out.println("系统日期" + dt.getDate());
     
    }
    }
     
    class DateTime
    {
    private Calendar calendar = null;
    public DateTime()
    {
    this.calendar = new GregorianCalendar();
    }
    public String getDate()//得到一个日期,格式为"yyyy-MM-dd HH:mm:ss:SSS"
    {
    //考虑到程序要频繁修改字符串,所以使用StringBuffer提升性能
    StringBuffer buf = new StringBuffer();
    buf.append(calendar.get(Calendar.YEAR)).append("-");//增长年
    buf.append(this.addZero(calendar.get(Calendar.MONTH)+1,2)).append("-");;
    buf.append(this.addZero(calendar.get(Calendar.DAY_OF_MONTH)+1,2)).append("-");
    buf.append(this.addZero(calendar.get(Calendar.HOUR_OF_DAY)+1,2)).append(":");
    buf.append(this.addZero(calendar.get(Calendar.MINUTE)+1,2)).append(":");
    buf.append(this.addZero(calendar.get(Calendar.SECOND)+1,2)).append(":");
    buf.append(this.addZero(calendar.get(Calendar.MILLISECOND)+1,2));
    return buf.toString();
     
     
    }
    //考虑到日期中存在前导0,所以在此处加上补零的方法。
    private String addZero(int num,int len)
    {
    StringBuffer s = new StringBuffer();
    while(s.length() < len)//如果长度不足,则继续补零
    {
    s.insert(0, "0");//在第一个位置处补0
    }
    return s.toString();
    }
    }



    -----------------------------------------------------------------------------------------------------------------------------------------------------------------------
        public class DateDemo01 {
            public static void main(String[] args) throws ParseException {
                Scanner sc = new Scanner(System.in);
                // String strDate = "2016-3-18 00:27:12:555";
                //
                // //准备第一个模板,从字符串中提取出日期数字
                // String pat1 = "yyyy-MM-dd HH:mm:ss:SSS";
                // //准备第二个模板,将提取后的日期数字变为指定的格式
                // String pat2 = "yyyy年MM月dd日 HH时mm分ss秒SSS毫秒";
                //
                // SimpleDateFormat sdf1 = new SimpleDateFormat(pat1);//实例化模板
                // SimpleDateFormat sdf2 = new SimpleDateFormat(pat2);//实例化模板
                //
                // Date d = null;
                // try {
                // d = sdf1.parse(strDate);
                // System.out.println(sdf1.format(d));
                // } catch (ParseException e) {
                // // TODO Auto-generated catch block
                // e.printStackTrace();
                // }
                // System.out.println(sdf2.format(d));
     
                // //精确到秒
                // Date date1 = new Date(); //获取当前计算机的日期时间对象
                // System.out.println(date1);
                // System.out.println(date1.getTime());
                // //java.sql.Date
                // //精确到毫秒
                // java.sql.Date date2 = new java.sql.Date(date1.getTime());
                // System.out.println(date2);
                // //精确到纳秒
                // java.sql.Timestamp date3 = new java.sql.Timestamp(date2.getTime());
                // System.out.println(date3);
                // Date date4 = new Date(date3.getTime());
                // //所有的日期时间,只要知道毫秒值就能创建该类型的对象,之间可以互相转换。
                //
                // //字符串转成日期
                // System.out.println("出生日期");
                // String birthday = sc.next();
                // //转成日期类型
                //
                // java.sql.Date dbirthday = java.sql.Date.valueOf(birthday);
                // System.out.println(dbirthday);
     
                // SimpleDateFormat
                // Date date1 = new Date();
                // System.out.println(date1);
                //设计日期的转换格式
                //  SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                //  //把date1以sdf指定的格式进行转换
                //  String sdate1 = sdf.format(date1);
                // System.out.println(sdate1);
                // 输入字符串,将字符串转成日期对象
     
     
                //  System.out.println("请输入日期,yyyy-MM-dd");
                //  String vdate = sc.nextLine();
                //  SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        
                // 将字符串日期转成Date对象
                //  Date date = sdf.parse(vdate);
                //  System.out.println(date);
                // 将日期转成(yyyy年MM月dd日)
        
                //  sdf = new SimpleDateFormat("yyyy年MM月dd日");
                //  String mydate = sdf.format(date);
                //  System.out.println(mydate);
        
                Calendar c = Calendar.getInstance();
                System.out.println(c.get(Calendar.YEAR));
                }
            }


     

    ——String类 
        String类是final类,不能有子类对象,也不能复写String类的方法。
        1、字符串是一个特殊的对象。
            String st = new String();     // String st = "abc";
        2、字符串一旦初始化就不可以被改变。
            String str1 = "abc";
            str1 = “def”;
            System.out.println(str1);
            输出结果为:def   但是字符串“abc”本身没有变化,变化的是str1的地址指向。对象没变,变化的是引用变量。
        3、字符串的定义
            String str1 = "abc";        //str1是一个类类型变量,“abc”是一个对象。
            String str2 = new String("abc");
        有什么区别?
            str1在内存中有一个对象,str2在内存中有两个对象,new String()和“abc”
            在内存中有一个常量池,常量池是一个数组
            使用起来是一样的,但是
                System.out.println(str1 == str2);    结果为false,因为str1和str2是两个对象。
                System.out.println(str1.equals(str2));    结果为true,因为String类复写了Object类中的equals方法,功能是将此字符串与指定的
                                                                              对象比较,判断字符串是否相同。
        4、字符串的获取和判断
            String s1 = "abc";
            String s2 = new String("abc");
            String s3 = "abc";
            System.out.ptintln(s1 == s2);
            System.out.println(s1 == s3);
            s1 == s2 运行结果为false;
            s1 == s3 运行结果为true,因为作为一个已经在常量池中存在的字符串,不会再开辟新的内存空间,因为再开辟空间的话会浪费空间
            获取:
                (1)字符串中包含的字符数,也就是字符串的长度。
                    int length(); 获取长度。
                        数组也有length,但是这是数组的属性,数组的length不带括号,而字符串的length是方法。
                (2)根据位置获取位置上的某个字符
                    char charAt(int index);
                (3)根据字符获取该字符在字符串中的位置
                    int indexOf(int ch);//函数重载
                        参数为ASCII码,如果有两个相同的字符,返回的是ch在字符串中第一次出现的位置。如果没有找着,返回-1。 
                    int indexOf(int ch,int fronIndex);从fromIndex指定位置开始,获取ch在字符串中出现的位置。
                (4)根据字符串获取小串在大串中的位置。
                    int indexOf(String str);
                    int indexOf(String str,int fromIndex);
                        输出脚标还是从0开始计算,如果定位大于字符串所在位置,则返回-1,如果字符串不存在,则返回-1;
                (5)反向索引,从右向左开始查找,但是下标不会变,还是1、2、3、4、5、6
                    int lastindexOf(int ch);
                    int lastindexOf(int ch,int fromIndex);
                    int lastindexOf(String str);
                    int lastindexOf(String str,int fromIndex);
                    如果查找的字符或字符串不存在,则返回-1。
                (6)获取字符串中的一段字符串。
                    String substring(int begin);
                        从指定位置开始到结尾,如果脚标不存在,会出现脚标越界异常。
                    String substring(int begin,int end);
                        包含头,但不包含尾。
                        该方法也可以从指定位置开始获取到结尾的字符串:
                            String substring(int begin,s.length());
            判断:
                (1)字符串中是否包含某一个子串。
                    boolean contains(str);
                    特殊之处:
                        indexOf(str)可以索引str第一次出现的位置,如果返回-1,表示str不存在于该字符串,所以,也可以用于判断是否包含。
                        if(str,indexOf("aa") != -1)        该方法既可以判断,又可以获取出现的位置。
                (2)字符串中是否有内容。
                    boolean isEmpty();
                        当且仅当length()为0时返回true。“”和null不同,“”是个对象,运行结果为true,null是指向空。
                (3)字符串是否以指定内容开头。
                    boolean startsWith(str);
                (4)字符串是否以指定内容结尾。
                    boolean endsWith(str);
                (5)判断字符串内容是否相同,复写了Object类中的equals方法。
                    boolean equals(str);
                (6)判断内容是否相同,并忽略大小写。
                    boolean equalsIgnoreCase();
            转换:
                (1)将字符数组转成字符串
                    构造函数:
                        String(char[ ])
                        String(char[ ],offset,count)
                        例:
                            char [ ] arr ={a,b,c,d,e,f,g};
                            String st = new String(arr,1,3);
                            System.out.println(st);
                            输出结果为:bcd            arr是数组,1是起始位,3是个数。
                    静态方法:
                        static String copyValueOf(char[ ]);
                        static String copyValueOf(char[ ] data,int offset,int count);
                (2)将字符串转成字符数组
                        char[ ] toCharArray()        该方法没有参数,因为是字符串调用,字符串就是对象。
                (3)将字节数组转成字符串
                        String(byte[ ])
                        String(byte[ ],offset,count)    将字节数组中的一部分转成字符串。
                (4)将字符串转成字节数组
                    byte[ ] getBytes()
                        字符串和字节数组在转换过程中,是可以指定编码表的。
                (5)将基本数据类型转成字符串
                    static String valueOf(int i);
                        返回int参数的字符串表示形式。
                            8+" "和valueOf(8)是一样的
                    static String valueOf(double d);
                        返回double参数的字符串表示形式。
                    static String valueOf(float f);
                        返回float参数的字符串表示形式。
                    static String valueOf(char c);
                    static String valueOf(boolean b);
                        返回boolean参数的字符串表示形式。
                    static String valueOf(Object obj);
                        返回Object参数的字符串表示形式。
                    static String valueOf(long l);
            替换:
                (1)新字符替换旧字符,然后返回一个新字符串。
                    String replace(char oldChar,char new Char)
                        如果要替换的字符不存在,返回的还是原串。
                (2)新字符串替换旧字符串,然后返回一个新字符串
                    String replace(CharSequence target,CharSequence replacement)
            切割:
                (1)将参数作为分隔符分开,以字符串数组形式返回。
                    String[ ] split(regex)
                    例:
                        String s = "zhangsan,lisi,wangwu";
                        String [ ] arr = s.split(",");
                        for(int i = 0; i < arr.length; i++)
                            System.out.println(arr[i]);
                    则输出结果为:
                        zhangsan
                        lisi
                        wangwu
            大小写转换
                (1)将字符串转换成大写
                    String toUpperCase()
                (2)将字符串转换成小写
                    String toLowerCase()
            去除空格
                将字符串两端的空格去除
                    String trim();
            比较
                对两个字符串进行自然顺序的比较
                    int compareTo(String st)
                        如果参数字符串等于此字符串,则返回值为0;如果此字符串小于参数字符串,则返回负数;如果此字符串大于参数字符串
                        ,则返回正数。

    ——StringBuffer
        1、字符串的组成原理就是通过该类实现的。
        2、StringBuffer可以对字符串内容进行增删。
        3、StringBuffer是一个容器。
        4、StringBuffer很多方法和String相同。
        5、StringBuffer长度可变化。
        StringBuffer是字符串缓冲区,是一个容器。
        特点:
            具备增删改查(CURD)。
            长度是可变化的。
            可以直接操作多个数据类型。
            可以通过toString方法变成字符串。
                当数据类型不确定而且长度也不确定,最终变成字符串的时候可以使用StringBuffer。
            (1)存储
                追加 append
                    StringBuffer append();
                    将指定数据作为参数添加到已有数据的结尾处。
                    StringBuffer sb = new StringBuffer();
                    sb.append("abc").append(true).append(123);
                        方法调用链:返回的还是本类对象,所以还可以调用本类方法。
                插入 insert
                    StringBuffer insert(index,数据);
                        将数据插入到指定index位置。
            (2)删除
                StringBuffer delete(start,end);删除缓冲区中的数据,包含头不包含尾。
                StringBuffer deleteCharAt(index);删除指定位置的字符。
            (3)获取
                char charAt(int index);
                    通过位置获取字符。
                int indexOf(String str);
                    通过字符串获取位置。
                int lastIndexOf(String str);
                    通过字符串反向索引。
                int length();
                String subString(int start,int end);
                    注意,该方法返回的还是一个String,并不是StringBuffer。
            (4)修改
                StringBuffer replace(int start,int end,String str);
                    将指定位置的字符串替换成参数str,包含头不包含尾。
                void setCharAt(int index,char ch);
                    注意,该方法无返回值,只替换,不返回。
            (5)反转
                StringBuffer reverse();
            (6)将缓冲区中的指定数据存储到指定字符数组中。
                void getChars(int srcBegin,int srcEnd,char[ ] dst,int dstBegin);
                    —从srcBegin处开始复制。
                    —在srcEnd处结束复制。
                    —dst用来保存复制数据的数组。
                    —从dst数组的dstBegin处开始保存。
            (7)JDK1.5版本之后出现了StringBuilder
                StringBuffer是线程同步。
                StringBuilder是线程不同步。
                单线程用StringBuilder。
                多线程用StringBuffer,多线程也可以用StringBuilder。自己加锁。
                建议使用StringBuilder。
                方法不变,功能相同,区别在于锁,StringBuilder无锁,需要自己加锁。
                锁不重要,效率最重要。
                JDK升级的三个因素:
                    1、提高效率
                    2、简化书写
                    3、提高安全性

    ——基本数据类型对象包装类
        byte        Byte
        short       Short
        int           Integer
        long        Long
        boolean  Boolean
        float        Float
        double    Double
        char        Character

        基本数据类型对象包装类的最常见作用就是用于基本数据类型和字符串类型之间做转换。
            (1)基本数据类型转成字符串:
                基本数据类型+“ ”
                基本数据类型.toString(基本数据类型值);
                例:Integer.toString(123);
            (2)字符串转成基本数据类型
                静态:
                    xxx a = Xxx.parseXxx(String);
                    int a = Integer.parseDouble("123");
                        将字符串参数作为有符号的十进制正数进行解析。
                    double b = Double.parseDouble("11.22");
                    boolean bool = Boolean.parseBoolean("true");
                非静态:
                    Integer i = new Integer("123");
                        构造一个新分配的Integer对象,它表示String参数所指示的int值。
                    int num = i.intValue();
            (3)十进制转成其他进制
                    toBinaryString();
                    toHexString();
                    toOctalString();
            (4)其他进制转成十进制
                    parseInt(String,radix);
        JDK1.5新特性
        public class Demo3

        {
            public static void main(String[] args)
            {
                Integer x = 4;//自动装箱。//new Integer(4);
                x = x + 2;//相当于x.intValue()//x+2:进行自动拆箱,变成了int型再和2进行加法运算,再将和进行装箱赋给X。
                System.out.println(x);
                Integer m = 128;
                Integer n = 128;
                System.out.println("m==n:"+(m==n));
                Integer a = 127;
                Integer b = 127;
                System.out.println("a==b:"+(a==b));
                //m==n结果为false
                //a==b结果为true,因为a和b指向了同一个Integer对象。
                //因为当数值在byte范围内中,对于新特性,如果该数值已经存在,则不会再开辟新空间。
            }
        }


     ——Collection集合类(集合框架)
        Collection集合方法:
            增:boolean add(E e)
            删:boolean remove(Object o)    void clear()
            查:boolean retainAll(Collection c)    int size()
            判断:boolean contains(Object o)    boolean isEmpty()

        1、为什么出现集合类
            面向对象语言对事物的体现都是以对象的形式,所以为了方便对多个对象的操作,就对对象进行存储,集合就是存储对象最常用的
            一种方式。
        2、数组和集合类同是容器,有何不同?
            数组虽然也可以存储对象,但长度是固定的;集合长度是可变的。数组中可以存储基本数据类型(同一种数据类型),集合只能存
            储对象(多种类型)。
        3、集合类的特点
            集合只用于存储对象,集合长度是可变的,集合可以存储不同类型的对象。
            注意:集合和数组一样,存放的都是对象的引用(地址)。
        4、Collection类的方法
            boolean add(E e)
                add方法的参数类型是Object,以便接受任意类型的对象。
                add方法是把对象的地址值添加到集合对象中。 
            boolean addAll(Collection c)
                添加一组元素。
            void clear()
                清空容器。
            boolean remove(Object o)
                删除一个元素。
            boolean removeAll(Collection c)
                删除一组元素,非并全部。
            boolean contains(Object o)
                判断是否包含指定元素。 
            boolean containsAll(Object o)
                判断是否包含指定的一组元素。
                对象存放顺序不同也为真。
            boolean equals(Object o)
                比较对象。对象存放顺序不同为假。
            int hashCode()
                返回此collection的哈希值。
            boolean isEmpty()
                判断是否为空。
                如果返回值为0,则isEmpty为true。
            int size()
                返回此collection的元素个数。
            boolean retainAll(Collection c)
                取交集。
            Object[ ] toArray()
                返回包含此collection中所有元素的数组。
            Iterator iterator()
                返回在此collection的元素上进行迭代的迭代器。
    ——迭代器 iterator
        迭代器其实就是集合取出元素的方式。
        Iterator是一个接口。
        1、迭代器成员方法
            boolean hasNext()
                如果仍有元素可以迭代,则返回true。
            E next()
                返回迭代的下一个元素。
            void remove()
                    从迭代器指向的collection中移除迭代器返回的最后一个元素。

    ——内部类实现接口的方式
        把取出方式定义在集合的内部,这样取出方式就可以直接访问集合内部的元素,那么取出方式就被定义成了内部类。而每一个容器的数据结构也不同,所以取出动作细节也不一样,但是都有共性内容:判断和取出,那么可以将这些共性抽取,形成一个接口。那么这些内部类都符合一个规则,该规则是Iterator。
        如何获取集合取出方法的对象呢?
            通过一个对外提供的方法:iterator();

    ——List集合共性方法
        List:
            凡是可以操作脚标的方法都是该体系特有的方法。
        增:
            void add(int index,E element);
            boolean addAll(int index,Collection c);
        删:
            E remove(int index);
                remove方法会返回被移除的元素。 
        改:
            E set(int index,E element);
        查:
            E get(int index);
            List subList(int fromIndex,int toIndex);
                返回子列表,包含头不包含尾。
            int indexOf(Object o);
                通过对象获取对象位置。
     
     
        Collection
            |--List:元素是有序的,元素可以重复,因为该集合体系有索引。
                |--ArrayList:底层的数据结构使用的是数组结构。特点:查询快,增删慢,相对于Vector,线程不同步,增量增加50%,允许null
                |--LinkedList:底层使用的是链表数据结构。特点:查询慢,增删快,允许null。
                |--Vector:底层是数组数据结构,因为线程同步,效率低,被ArrayList替代了,增量翻倍。
                |--Stack:继承了Vector,实现了堆栈操作 
            |--Set:元素是无序的,元素不可以重复,因为该集合无索引。
                无序:存入和取出的顺序不一致。
                |--HashSet:底层数据结构是哈希表。
                |--TreeSet:可以对Set集合中的元素进行排序。(自然排序,按照ASCII码表进行排序)

     
        import java.util.*;
     
        public class ListDemo {
            public static void main(String[] args)
            {
                ArrayList al = new ArrayList();
                //增
                al.add("01");
                al.add("02");
                al.add("03");
                System.out.println("原集合为:"+al);
                al.add(1,"05");
                System.out.println("增加后集合元素为:"+al);
                //删
                al.remove(2);
                System.out.println("删除后集合元素为:"+al);
                //改
                al.set(2, "22");
                System.out.println("改变后集合元素为:"+al);
                //查
                for(int i = 0;i<al.size();i++)
                {
                    System.out.print("al.get("+i+")="+al.get(i)+" ");
                }
                Iterator it = al.iterator();
                //在迭代过程中添加或删除元素
                while(it.hasNext())
                {
                    Object obj = it.next();
                    if(obj.equals("22"))
                    //al.add("08");在迭代过程中,既用迭代器又用集合,会产生并发异常ConcurrentModificationException
                    //当方法检测到对象的并发修改,但不允许这种修改时,抛出此异常。
                    it.remove();//此代码运行之后会将22这个元素的引用从集合中删除,但是obj仍然指向该对象,22仍然存在于内存中
                    System.out.println(obj);
                }
                System.out.println(al);
            }
        }

    ——List集合特有的迭代器,ListIterator是Iterator的子接口。
        在迭代时,不可以通过集合对象的方法操作集合中的元素,否则会产生并发异常ConcurrentModificationException,所以在迭代时,
        只能用迭代器的方法操作元素,可是Iterator的方法是有限的,只有hasNext、next和remove方法,只能对元素进行判断,取出,删
        除的操作。如果想要进行其他的操作,比如添加修改等,就需要使用其子接口ListIterator。该接口只能通过List集合的listIterator方法
        获取。

        ListIterator方法:
            void add(E e)
                插入元素。
            void remove()
                删除元素。
            void set(E e)
                用指定元素替换next或者previous返回的最后一个元素。
            E previous();

                逆向遍历。
            boolean hasPrevious();

                如果迭代器前有元素,则返回true;和hasNext()相反。 
     
        import java.util.ArrayList;
        import java.util.ListIterator;
     
        public class ListIteratorDemo {
            public static void main(String[] args)
            {
                ArrayList al = new ArrayList();
                al.add("01");
                al.add("02");
                al.add("03");
     
                ListIterator lt = al.listIterator();
                System.out.println(al);
                while(lt.hasNext())
                {
                    Object obj = lt.next();
                    /*if(obj == "03")
                    lt.add("04");*/
                    if(obj.equals("03"))
                    //lt.add("05");
                    li.set("007"); 
                }
                System.out.println(al);
            }
        }

    ——LinkedList方法
        void addFirst(E e)
            将指定元素插入此列表的开头。
        void addLast(E e)
            将指定元素添加到此列表的尾部。
        在JDK1.6版本之后,出现了offerFirst和offerLast,与addFirst和addLast功能相同,区别在于:offerFirst和offerLast返回值为boolean
        E getFirst()
            返回此列表的第一个元素。
        E getLast()
            返回此列表的最后一个元素。
        如果此列表为空,则抛出NoSuchElementException异常。
        在JDK1.6版本之后,出现了peekFirst和peekLast,与getFirst和getLast功能相同,区别在于:如果此列表为空,不抛异常,返回null。
        E removeFirst()
            返回并删除第一个元素。
        E removeLast()
            返回并删除最后一个元素。
        如果此列表为空,则抛出NoSuchElementException异常。
        在JDK1.6版本之后,出现pollFirst和pollLast,与removeFirst和removeLast功能相同,区别在于:如果此列表为空,不抛异常,返
        回null。

    ——Vector方法
        枚举是Vector类的特有迭代器。
            Enumeration elements()
                Enumeration en = v.elements();
            boolean hasMoreElements()
                判断是否还有元素。
            E nextElement()
                返回下一个元素。

        Enumeration底层数据结构是哈希表,元素是无序的。

        枚举和迭代器是一样的,因为枚举方法名过长,所以被迭代器替换了。 
        
        Vector增量翻倍。

        枚举只有Vector有。 

        void addElement(E obj)
            将指定的组件添加到此向量的末尾,将其大小增加1。
        int capacity()
            返回此向量当前容量。
        boolean contains(Object o)
            如果此向量包含指定的元素,则返回true。 

        E elementAt(int index)
            根据位置获取元素。
        Enumeration elements()
            返回此向量的组件的枚举。
        ..........略

    ——Stack
        Stack继承了Vector类,实现了堆栈操作。
        Stack类方法
            boolean empty()
                判断堆栈是否为空。
            E peek()
                获取栈顶对象,但不移除栈顶对象。
            E pop()
                移除栈顶对象并返回被移除的对象。
            E push(E e)
                将元素压入栈顶。
            int search(Object o)
                根据对象返回对象在堆栈中的位置,以1为基数(数组中以0位基数) 

    ——用LinkedList模拟出队出栈

        import java.util.*;
     
        class Zhan
        {
            private LinkedList link;
            Zhan()
            {
                link = new LinkedList();
            }
            public void method_add(Object obj)
            {
                link.addLast(obj);
            }
            public Object method_get()
            {
                return link.pollLast();
            }
        }
     
        class Duilie
        {
            private LinkedList link;
            Duilie()
            {
                link = new LinkedList();
            }
            public void method_add(Object obj)
            {
                link.addLast(obj);
            }
            public Object method_get()
            {
                return link.pollFirst();
            }
        }
     
        public class LinkedListDemo {
            public static void main(String[] args)
            {
                Zhan z = new Zhan();
                for(int i = 0; i < 5; i++)
                {
                    Scanner sc = new Scanner(System.in);
                    String st = sc.next();
                    z.method_add(st);
                }
                System.out.println("出栈:");
                for(int i = 0;i < 5;i++)
                {
                    System.out.println(z.method_get());
                }
                Duilie d = new Duilie();
                for(int i = 0; i < 5;i++)
                {
                    Scanner sc = new Scanner(System.in);
                    String st = sc.next();
                    d.method_add(st);
                }
                System.out.println("出队");
                for(int i = 0; i < 5; i++)
                {
                    System.out.println(d.method_get());
                }
            }
        }


    ——ArrayList去除重复的元素

        import java.util.*;
     
        public class ArrayListDemo {
            public static void main(String[] args)
            {
                ArrayList al = new ArrayList();
                al.add("01");
                al.add("02");
                al.add("03");
                al.add("04");
                al.add("01");
                al.add("02");
                System.out.println(al);
                al = SingleElement(al);
                System.out.println(al);
            }
            public static ArrayList SingleElement(ArrayList al)
            {
                ArrayList newal = new ArrayList();
                Iterator it = al.iterator();
                while(it.hasNext())
                {
                    Object obj = it.next();
                    if(!newal.contains(obj))
                    {
                        newal.add(obj);
                    }
                }
                return newal;
     
            }

        } 
        
    ——ArrayList去除重复对象

        import java.util.*;
     
        class Person
        {
            private String name;
            private int age;
            Person(String name,int age)
            {
                this.name = name;
                this.age = age;
            }
            public boolean equals(Object obj)
            {
                if(!(obj instanceof Person))
                    return false;
                Person p = (Person)obj;
                return this.name.equals(p.name) && this.age == p.age;
            }
            public String getName()
            {
                return this.name;
            }
            public int getAge()
            {
                return this.age;
            }
        }
     
        public class ArrayListDemo2 {
            public static void main(String[] args)
            {
                ArrayList al = new ArrayList();
                al.add(new Person("wang1",21));
                al.add(new Person("wang2",22));
                al.add(new Person("wang1",21));
                al.add(new Person("wang4",24));
                al.add(new Person("wang3",23));
                al.add(new Person("wang2",22));
                al = Equals(al);
                Iterator it = al.iterator();
     
                while(it.hasNext())
                {
                    Person p = (Person)it.next();//如果不向下转型,则多态编译失败
                    System.out.println(p.getName()+"..."+p.getAge());
                }
            }
            public static ArrayList Equals(ArrayList al)
            {
                ArrayList newal = new ArrayList();
                Iterator it = al.iterator();
                while(it.hasNext())
                {
                    Object obj = it.next();
                    if(!newal.contains(obj))
                    {
                        newal.add(obj);
                    }
                }
                return newal;
            }
     
        }


    ——Set集合
        Set集合共性方法与Collection集合共性方法一致。
    ——HashSet
        HashSet特点:
            无序
            不可重复

        Set:元素是无序的(存入和取出的顺序不一定一致),元素不可以重复,因为该集合无索引。
           |--HashSet:底层数据结构是哈希表,线程是不同步的。
           |--TreeSet:可以对Set集合中的元素进行排序。(自然排序,按照ASCII码表进行排序)
        Set集合的功能和Collection集合是一致的。
     
        哈希表的存放顺序:按照哈希值的大小由小到大存储。(该顺序有可能和存入的顺序不一致)
        取的时候按照哈希值取。
        public int hashCode();
            返回此对象的哈希值。
        当哈希表中两个对象的地址值相同时,哈希表还有一次校验方式:
            那就是判断元素对象是否相同(equals()方法)。
            地址值相同但并不是同一个对象的情况下,在当前地址值下顺延,再添加一个对象(哈希值),这两个对象都在同一个哈希值上。
        Set集合的取出方式只有一种,就是迭代器。
        Set中的add()方法返回的是布尔型的值,因为当存在相同哈希值元素的情况下,判断结果为同一个元素,存入失败,返回false。
     
       当往HashSet里存元素的时候,一般都会复写HashCode()和equals()方法。
       总结:
           HashSet是如何保证元素唯一性的呢?
               是通过元素的两个方法:hashCode和equals来完成。
               如果元素的hashCode值相同,会判断equals是否为true。
               如果元素的hashCode值不同,不会调用equals。
        注意:对于判断元素是否存在,以及删除等操作,依赖的方法是元素的hashCode和equals方法。
              先判断哈希值,再判断是否是同一个对象,HashSet中的对象必须复写equals方法才能判断值是否相同。
              而ArrayList判断元素是否存在和删除元素只依赖equals方法。
        关于哈希值和地址:
            哈希值和地址值是不一样的,哈希值是通过哈希算法散列得来的,而地址值是通过是和物理层面有关,是系统分配的,是不存在相
            同的,而哈希值是可以通过强制手段设置为相同的,也就是说哈希值是一种逻辑上的确保唯一性,而地址值就是物理上确保唯一性。
        package set;
        import java.util.HashSet;
        import java.util.Iterator;
        /**
         * 
         * 2016年2月29日19:48:35
         * 
         * 去除HashSet中的重复元素
         * 
         * 
         * */
        public class HashSetDemo {
             public static void main(String[] args)
             {
                  HashSet hs = new HashSet();
                  hs.add(new Person("lisi01",11));
                  hs.add(new Person("lisi02",12));
                  hs.add(new Person("lisi03",13));
                  hs.add(new Person("lisi03",13));
                  hs.add(new Person("lisi04",14));
                  hs.add(new Person("lisi04",14));
                  hs.add(new Person("lisi05",15));
                  hs.add(new Person("lisi06",16));
                  hs.add(new Person("lisi06",16));
                  hs.add(new Person("lisi06",16));

                  for(Iterator it = hs.iterator();it.hasNext();)
                  {
                       Person p = (Person)it.next();
                       System.out.println(p.getName() + "  " + p.getAge());
                  }
             }
        }
        class Person
        {
             private String name;
             private int age;
             Person(String name,int age)
             {
                  this.name = name;
                  this.age = age;
             }
             public String getName()
             {
                  return name;
             }    
             public int getAge()
             {
                  return age;
             }
             public boolean equals(Object o)
             {
                  if(!(o instanceof Person))
                       return false;
                  Person p = (Person)o;
                  return p.getAge() == this.getAge() && p.getName().equals(this.getName());
             }
             public int hashCode()
             {
                  return name.length() + age*7;
             }
        }
     
    ——TreeSet:
            往TreeSet里面存对象,TreeSet集合是要进行排序的,所以要存入的对象必须具有比较性,java.lang中的Comparable接口会强制
        对实现它的每个类的对象具备比较性。
            TreeSet中存入的对象必须强制实现Comparable接口并复写compareTo()方法。 
            Conparable接口中只有一个方法:
                int compareTo(T o)
            比较此对象与指定对象的顺序,如果this大于o,返回1;如果相等返回0;如果o大于this,返回-1。
            注意:
                    compareTo()方法中只能传对象,如果是基本数据类型,需要装箱。
                        new Integer(12);
                    将整型数据封装成整型对象。 
        TreeSet默认是升序排序,如果想改为降序排序,可以将compareTo方法的返回值改为1-> -1,-1->1。
        所以如果想在TreeSet中存储对象,该对象所在的类必须先实现Comparable接口,因为往TreeSet中存储对象时,JVM会自动调用
        compareTo方法来进行判断排序,如果排序时当主要条件相同,可以判断次要条件(需要通过复写来自定义compareTo方法)。
            例如:
                if(this.age == s.age)
                {
                    return this.name.compareTo(s.name);    //当年龄相同时再判断姓名,因为String类已经实现Comparable接口,所以可以直
                                                                                      接使用compareTo方法。
                } 
        TreeSet和HashSet的区别是TreeSet存储的对象所在的类需要复写compareTo方法,可以在compareTo方法中复写自己的比较方法。
        TreeSet集合只看compareTo方法返回的结果是整数还是负数还是零。如果返回值固定位1,则存储顺序是什么取出顺序就是什么,
        如果compareTo返回的是1,则表示存入的数比第一个数大,所以存储顺序是固定的。

        TreeSet保证数据唯一性的依据:
            compareTo方法的返回值,TreeSet集合存储顺序与哈希值无关,只有HashSet才依据哈希值来判断元素。
            TreeSet是通过compareTo方法来判断元素是否相同,只要不返回0,就存入元素,返回值为1升序存储,返回值为-1降序存储。
            要想使用TreeSet删除或者判断元素是否相同,都是依据compareTo方法。
            
        TreeSet排序的第一种方法:
            让元素自身具备比较性,继承comparable借口,复写compareTo方法,这种方式也被称为自然顺序,或者默认顺序,因为继
            承Comparable接口之后元素自身已经具备比较行,并且是按照字典顺序排序。

        TreeSet的第二种比较方式:
            当元素自身不具备比较性时,或者具备的比较性不是所需要的,可以定义一个比较器,在集合初始化时,将比较器Comparator传
            递给TreeSet使其具备比较性。

        TreeSet集合的构造方法:
            TreeSet()
                构造一个空的集合,根据元素的自然顺序进行排序
            TreeSet(Comparator c)
                构造一个空的集合,它根据指定比较器进行排序。
            如果同时存在复写compareTo和传入比较器,则以比较器为准。

        定义比较器:
            定义一个类,实现Comparator接口,并复写compare方法。
            Comparable中是compareTo方法,Comparator中是compare()方法,这两个方法都是以返回值来判断元素是否相同。

        TreeSet底层数据结构:
            因为每次存入对象,都要与所有对象都比较一遍,效率低下,为了优化效率,TreeSet底层使用二叉树来存储,比第一个元素小的
            往左放,比第一个元素大的往右放,然后跟第二层比较,小的往左放大的往右放……当数据多了之后依然效率低下,为了解决该
            现象,二叉树结点多了之后会自动折中,取一个中间值继续进行比较。
            二叉树元素的取出方式:
                由小到大的取出方式:
                    因为小值全都存放在左边,所以先取左边,(中序遍历)
        
        TreeSet练习:
     
        import java.util.Comparator;
        import java.util.Iterator;
        import java.util.Scanner;
        import java.util.TreeSet;
     
        /*
         * 2016年3月9日23:40:04
         * 
         * 要求:往TreeSet中存字符串,并以字符串长度进行排序
         * 
         * */
        public class TreeSetTest {
            public static void main(String[] args)
            {
                    Scanner sc = new Scanner(System.in);
                    TreeSet ts = new TreeSet(new MyComparator3());    //传入比较器
                    String s1 = new String(sc.next());
                    String s2 = new String(sc.next());
                    String s3 = new String(sc.next());
                    String s4 = new String(sc.next());
                    ts.add(sc.next());
                    ts.add(sc.next());
                    ts.add(sc.next());
                    ts.add(sc.next());
     
                    for(Iterator it = ts.iterator(); it.hasNext();)
                    {
                            System.out.println(it.next().toString());
                    }
            }
        }
     
     
        //定义比较器,用来接收字符串
        class MyComparator3 implements Comparator
        {
            public int compare(Object o1,Object o2)    //复写compare方法
            {
                if(o1.toString().length() > o2.toString().length())
                {
                    return 1;
                }
                if(o1.toString().length() == o2.toString().length())
                {
                    //当字符串长度相等,再判断字符串内容    次要比较
                    return o1.toString().compareTo(o2.toString());
                }
                return -1;
     
     
    //          int num1 = new Integer(o1.toString().length());
    //          int num2 = new Integer(o2.toString().length());
    //
    //          if(num1 > num2)
    //          {
    //              return 1;
    //          }
    //              if(num1 == num2)
    //          {
    //              return o1.toString().compareTo(o2.toString());
    //          }
    //          return -1;
     
    //          String s1 = (String)o1;
    //          String s2 = (String)o2;
    //          int num = new Integer(s1.length()).compareTo(new Integer(s2.length()));    //必须将整型数据装箱才能进行compareTo比较
    //          if(num == 0)
    //          {
    //              return s1.compareTo(s2);
    //          }
    //          return num;
            }
        }
     
     
    ——泛型(广泛的类型)

        见到带泛型的类,用的时候往里传参数就可以了。
            ArrayList al  =  new ArrayList();

            al.add(“123123”);

            al.add(“123123”)

            al.add(123213);

            Strings = (String)it.next();
        如果将int 123213在取出过程中强制转换成Strign类型,则运行时会报错,而编译时不会报错,为了在解决这个安全问题 ,JDK1.5版
        本以后出现的新特性,用于解决安全问题,是一个安全机制。

        ArrayList<String> al = new ArrayList<String>()
            定义一个容器,里面的数据类型是String类型。
            如果数据类型不一致,可以将错误从运行时期转移到编译时期,提高安全性。 
     
        泛型的优点:
            1)将运行时期出现的问题ClassCastException转移到了编译时期,方便于程序员解决问题,让运行时期问题减少,提高安全性。
            2)提高扩展性,但是不能预先使用子类特有方法,因为并不确定要传什么类型的数据。
            3)可以将在代器中传入泛型,Iterator<String>,避免了强制转换的麻烦。
                如果不将迭代器Iterator加入泛型,则取出元素时(it.next())依然需要强制转换。 
                当使用JDK提供的数据类型时,Iterator不必使用泛型,当迭代器取出的是自定义对象时,为了避免强转强转的麻烦,可以加泛型
     
            “注: Demo.java使用了未经检查或不安全的操作。
            注: 有关详细信息, 请使用 -Xlint:unchecked 重新编译。”
            同时编译时期的操作提示也没了,因为安全了。
     
    ——泛型格式:
            通过<>来定义要操作的数据类型。

    ——泛型类
            就是带泛型的类。 
        在使用Java提供的对象时,什么时候写泛型呢?
            通常在集合框架中很常见,只要见到<>就要定义泛型。
            其实<>就是用来接收类型的,这个类型就是引用数据类型。
            ArrayList<E>            E代表Elements元素,T代表type类型
                |--    add(E e)
            当ArrayList接收的泛型为String时,则add方法中接收的参数也是String(add(String s)) 
            ArrayList<String>集合中只能传入String类型的数据,如果传入其它类型数据会编译错误。
            当使用集合时,将集合中要存储的数据类型作为参数传递到<>中即可。

    ——比较器Comparator中的泛型:
            Comparator<T>
                |--  compare(T1 t,T2 t2)

            class MyComparator implements Comparator<String>
            {
                public int compare(String s1, String s2)
                {
                    //在Comparator中加入泛型,可以避免将Object强转成所需类型,参数传入时就已经是指定类型了
                    //String s1 = (String)o1;
                    //String s2 = (String)o2;
                }
            } 
     
    ——什么时候定义泛型类?
            当类中要操作的引用数据类型(只能是引用数据类型)不确定的时候。
            早期在JDK1.5之前定义Object来完成扩展,因为Object能接收任意类型对象。
            在JDK1.5版本之后定义泛型来完成扩展。
        
        在JDK1.5版本之前,通常使用Object来接收不同类型数据。
        public class GenericDemo02 {
            public static void main(String[] args)
            {
                Tool t = new Tool();
                t.setObject(new Work());
                Work w = (Work)t.getObject();    //没有泛型之前,必须主观判断所要操作的类型。
            }
        }
        class Tool
        {
            private Object o;
            public void setObject(Object o)
            {
                this.o = o;
            }
            public Object getObject()
            {
                return o;
            }
        }
        class Work
        {
     
        }
        class Student
        {
     
        }
        
        在JDK1.5版本出现泛型之后,增强了安全性,强制传入数据类型必须一致。
        public class GenericDemo03 {
            public static void main(String[] args)
            {
                Tool2 t = new Tool2();
                t.setObject(new Work2());
                Work w = t.getObject();    //因为在Tool2中传入了泛型Student2,所以Tool中必须传入符合泛型。
            }
        }
        class Tool2<Work>
        {
            private Object o;
            public void setObject(Object o)
            {
                this.o = o;
            }
            public Object getObject()
            {
                return o;
            }
        }
        class Work2
        {
     
        }
        class Student2
        {
     
        }
     

        注意:
            equals方法不能使用泛型,只能使用Object o。
     
        import java.util.*;
        public class Demo
        {
            public static void main(String[] args)
            {
                Utils<Worker> u = new Utils<Worker>();
    //          u.setObject(new Student());    //如果创建集合时泛型传入的是Worker,则无法在setObject()中添加其他类型。
                u.setObject(new Worker());    //只能传入Worker类对象。
                Worker w = u.getObject();
            }
        }
        class Utils<AA>
        {
            private AA a;
            public void setObject(AA a)
            {
                this.a = a;
            }
            public AA getObject()
            {
                return a;
            }
        }
        class Student{}
        class Worker{}
     
    ——定义泛型方法
            如果要定义静态泛型,则泛型一定定义在方法上。 
            泛型定义在方法上时,放在返回值前面。
            为了让不同方法可以操作不同类型,而且类的类型还不确定,那么可以让泛型定义在方法上
                public <T> void show(T t){ }

        public class GenericDemo04 {
            public static void main(String[] args)
            {
                Demo d = new Demo();
                d.show("show");
                d.print(55);
            }
        }
        class Demo
        {
            public <T> void show(T t)
            {
                System.out.println("show + " + t);
            }
            public <Q> void print(Q q)
            {
                System.out.println("print + " + q);
            }
        }
     
            也可以将泛型同时定义在类和方法上。
                当类定义泛型之后,如果方法泛型与类泛型一致,则方法只能操作对应泛型。
                如果方法上单独定义泛型,则该泛型与类泛型无关。
                类泛型可以与方法泛型同名,以方法泛型为准。

        public class GenericDemo04 {
            public static void main(String[] args)
            {
                Demo<String> d = new Demo<String>();
                d.show(30);
                d.print(55);
            }
        }
        class Demo<T>
        {
    //      public <T> void show(T t)    //如果在方法上也定义泛型,则以方法泛型为准。 
            public void show(T t)    //此时show方法没有定义泛型,则所操作泛型必须与类接收泛型一致
            {
                System.out.println("show + " + t);
            }
            public <Q> void print(Q q)
            {
                System.out.println("print + " + q);
            }
        }
     
    ——泛型静态方法
            静态方法不能访问类上定义的泛型,因为类的泛型只有在创建对象的时候才会有泛型。
            只有在 Demo<String> d = new Demo<String>();才会传入泛型参数,而静态在类加载时就已经存在了,所以静态无法访问非静态。 
                public static void method(T t)//error
            如果静态方法操作的引用数据类型不确定,可以将泛型定义在方法上。
                public static <T> void method(T t)
            定义泛型不能乱写,泛型需要写在返回值前面。
                public static <T> void method(T t) 

    ——泛型接口
            当实现接口时无法确定要操作的数据类型,所以将接口定义为泛型。
            在实现接口的同时,在类上也加入泛型,使用方法同泛型类。

            public class GenericDemo05 {
                public static void main(String[] args)
                {
                    InterImp<Integer> in = new InterImp<Integer>();
                    n.show(55);
                    in.show(" ");    //因为InterImp实现了Inter<T>接口,并且在创建InterImp对象时,传入了Integer泛型,
                                           //所以无法操作String类型数据。
                }
            }
            class InterImp <T> implements Inter<T>
            {
                public void show(T t)
                {
                    System.out.println("Inter show + " + t);
                }
            }
            interface Inter<T>
            {
                public void show(T t);
            }
     
     
    ——泛型限定
            public class GenericDemo06 {
            public static void main(String[] args)
            {
                ArrayList<String> al1 = new ArrayList<String>();
                al1.add("111");
                al1.add("222");
                al1.add("333");
     
                ArrayList<Integer> al2 = new ArrayList<Integer>();
                al2.add(444);
                al2.add(555);
                al2.add(666);
                print(al1);
                print(al2);    //当传入的ArrayList泛型为Integer时,print无法操作,因为print的泛型为String,如果改为通用泛型就能操作了。
            }

    //public static <?> void print(ArrayList<?> al){}
    //当使用泛型T来接收而不是使用通配符?来接收时,可以使用T t引用来操作对象,而通配符不行。 
            public static void print(ArrayList<String> al)    //当参数改为ArrayList al时,程序编译也不会出错,因为后期出现的泛型应该向下兼容
            {
                for(Iterator<String> it = al.iterator(); it.hasNext();)
                {
                    System.out.println(it.next());
                }
            }
        }

    ——泛型限定占位符: 
            public static void method(ArrayList<?> al)
            ?是一个占位符,并不是具体类型,如果使用T的话就可以接收子类对象并进行操作。
                    //    public static void print(ArrayList<?> al){
                                Iterator<?> it = it.iterator();
                          }
                    //    当使用泛型T来接收而不是使用通配符?来接收时,可以使用T t引用来操作对象,而通配符不行。
                    public static <T> void print(ArrayList<T> al)
                    {
                        for(Iterator<T> it = al.iterator(); it.hasNext();)
                        {
                            T t = it.next(); 
                            System.out.println(t.geetName());
                        }
                    }
     
            泛型不能预先调用子类对象,但是如果泛型传入的是自定义类<T>,就可以调用自定义类中的方法。
                例如传入的是String
                    T t = it.next();
                    t.length();
            无法使用
                    it.next().length();
            如果要使用子类对象的特有方法,必须传入泛型,否则默认Object。 
            因为父类无法使用子类对象的特有方法。 
        使用自定义泛型传参时,左右两边的泛型要一致。
            ArrayList<Student> al = new ArrayList<Student>();//ok
            ArrayList<Person> al = new ArrayList<Student>();//error
        如果事先并不能确定要传入的数据类型,可以使用占位符?来接收Person或者Student类型的对象,占位符?可接收任意类型的对象。

         如果只想接收Person类型或者Person的子类,可以使用泛型限定。
            public static void method(ArrayList<? extends Person> al)
        泛型的限定:
            ? extends E:上限限定,可以接收E类型或者E的子类型。
            ? super E:下限限定,可以接收E类型或者E的父类型。
     
        自动装箱拆箱操作?
            自动装箱就是Java编译器在编译期间自动将基本类型包装成数据对象。
                integer num = new Integer(100);
            自动装箱后就变成了:
                Integer num = 100;
                将100自动转换为数据包装对象。 

            自动拆箱:
                将数据类型包装类转换成基本数据类型:
                    int num = new Integer(100);
     
     
     
    ——Map集合
        Map<K,V>
            public HashMap()
            加载因子:达到加载因子就进行扩容。
        Map
           |--Hashtable:底层是哈希表数据结构,不可以存入null键和null值,该集合是线程同步的。效率低。
                    此类实现一个哈希表,该哈希值将键映射到相应的值,任何非null的对象都可以用作键或值。
                    为了成功在哈希表中存储和获取对象,用作键的对象必须实现hashCode和equals方法。
           |--HashMap:底层是哈希表数据结构,允许使用null键和null值,该集合线程不同步。效率高。
           |--TreeMap:底层是二叉树数据结构,线程不同步,可以用于给Map集合中的键进行排序。
        和Set很像,其实Set底层就是使用了Map集合,Map存一对,而Set去掉一个,存一个。
     
        该集合存储键值对,一对一对往里存,而且要保证键的唯一性。
        Collection:单列集合。
        Map:双列集合。
        Map集合的共性方法:
            1)添加
                V put(K key,V value);
                    返回值是V,当向Map中存值的时候,如果键已经存在,则返回第一次存储的值,并保存第二次存储的值。(覆盖前一个值)
     
                V putAll(Map<? extendsK,? extends V>);
                    向Map集合中添加元素。 
                    Map中没有add方法,只有put方法。
                    将指定的值与指定的键相关联。
     
            2)删除
                void clear();
                     清空集合。
                V remove(Object key);
                    通过一个键来删除一个元素。
                remove的时候会通过键来删除元素并且返回该键对应的值。
            3)判断
                boolean containsKey(Object key);
                    判断是否包含某个键。
     
                boolean containsValue(Object value);
                    判断是否包含某个值。
     
                boolean isEmpty();
                    判断集合是否为空。
     
            4)获取
                V get(Object key)
                    通过某个键获取一个值。
                    get的键不存在时,返回null。
                HashMap中null是可以作为一个键存在的,所以get(null)可以获取相应的值。null作为值时意义相同。
     
                int size();
                    返回此哈希表中的键的数量。
     
                Collection<V> values();
                    返回一个集合。 
                Collection<String> coll = map.values();
                此时coll就可以获取迭代器来取出元素了。
                    Map<String,Integer> map = new HashMap<String,Integer>();
                    map.put("01", 11);
                    map.put("02", 12);
                    map.put("03", 13);
                    map.put("04", 14);
                    map.put("05", 15);
                    
                    Collection<Integer> set = map.values();
                    for(Iterator<Integer> it = set.iterator();it.hasNext();)
                    {
                        System.out.println(it.next());
                    }
     
                Set<Map.Entry<K,V>> entrySet();
                    返回此映射的映射关系的Set视图。
                    其实就是将键值对以对为单位存放到Set集合中,通过Map.Entry方法来获取Key和Value。 
     
                Set<K> keySet();
                    返回Map集合中的所有的键。 
     
        Map集合的两种取出方式:
            1)keySet();
                将Map中所有的键存入到Set集合中,因为Set集合具备迭代器。
                所以可以用迭代器的方式取出所有的键,再根据get方法获取每一个键对应的值。
                Map<String,Integer> map = new HashMap<String,Integer>();
                map.put("01",11); 
                map.put("02",12); 
                map.put("03",13); 
                map.put("04",14); 
                map.put("05",15); 

                //先使用keySet()方法获取Map集合中所有键的Set集合。
                //使用Set集合来接收所有的键,因为Set集合具备迭代器。
                //Set集合也具备泛型,所以最好使用泛型来接收keySet返回的键。

                Set<String> keyS = map.keySet();

                //迭代器Iterator的泛型和Set集合的泛型一致。 
                for(Iterator<String> it = keyS.iterator(); it.hasNext();)
                {
                    String key = it.next();
                    String value = map.get(key);
                    //有了键key,就可以通过Map集合的get方法获取其对应的值。
                    System.out.println("key = " + key + ",value = " + value);
                } 
     
            2)Set<Map.Entry<K,V>> entrySet();
                当Map集合调用entrySet的时候,返回的也是一个Set集合,也就是将Map集合中的映射关系取出。
                一个键对应一个值就是一个映射关系,这个映射关系就是Map.Entry类型,通过迭代器返回的值就是一个映射关系。
                一组映射关系就代表Map.Entry的实例对象,也就是it.next()取出的元素(对象),因为这个对象中既有key又有value,所
                以Map.Entry<K,V>中提供了getKey()和getValue()方法。 

                    for(Iterator<Map.Entry<String, Integer>> it1 = entryset.iterator();it1.hasNext();)
    {
    Entry e = it1.next();
    System.out.println(e.getValue());
    }

                key和value可以看做是丈夫和妻子,entrySet取出的既不是丈夫(key)也不是妻子(value),取出的是丈夫(key)和妻
                子(value)的关系,所以取出得到的值既不是丈夫(key)也不是妻子(value),而是Map.Entry。
                因为取到了key与value的关系,所以可以通过Map.Entry中的getKey()和getValue()方法获取关系中的键和值。 

    ——Map.Entry
            其实Entry也是一个接口,它是Map接口中的一个内部接口,Entry是Map集合的嵌套类。
            为什么Entry要定义成Map集合的内部接口?
                因为Entry表示的是Map集合的映射关系,所以必须先有Map集合才能有Entry。
                而且当Entry定义成内部类时,可以直接访问Map集合的内部元素。 

            Interface Map<T>
            {
                //能加static的接口一定是内部接口
                public static interface entry
                {
                    public abstract <T> K getKey();
                    public abstract <T> V getValue();
                }
            } 
            class HashMap implements Map
            {
                class HaHa<K,V> implements Map.Entry<K,V>
                {
                    public K getKey(){}
                    public V getValue(){}
                }
            } 
                
    ——Collections-sort

     
        Collections专门用于对集合框架进行操作。
        Collections作为一个集合框架工具类,其方法都是静态的。
        它没有对外提供构造函数,是不需要创建对象的,因为它的对象中并未封装特有数据,都是共享数据。

        /**
         * 对List进行字典排序
         * 
         * @author Administrator
         *
         */
        public class SortDemo {
            public static void main(String[] args)
            {
                ArrayList<String> al = new ArrayList<String>();
                al.add("ass");
                al.add("kkk");
                al.add("ww");
                al.add("hhhhh");
                al.add("tttt");
                System.out.println("排序前:" + al);
                Collections.sort(al);
                System.out.println("排序后:" + al);
                Collections.sort(al,new StrLenComparator());
                System.out.println("对字符串进行长度排序:" + al); 
            }
        }
        class StrLenComparator implements Comparator<String>
        {
            public int compare(String s1, String s2)
            {
                if(s1.length() > s2.length())
                    return 1;
                if(s1.length() < s2.length())
                    return -1;
                return s1.compareTo(s2);
            }
        }
     
    ——Collections binarySearch

            binarySearch专门用于对List集合进行查找,因为List集合具备脚标,并且但凡能够使用二分查找的,必须是有序集合。
            用法与数组的二分查找相同。
            如果查找的规则并不是所需的规则,可以自定义比较器。

        ArrayList<String> al = new ArrayList<String>();
    al.add("a");
    al.add("b");
    al.add("c");
    al.add("d");
    al.add("e");
    al.add("f");
     
    System.out.println(Collections.binarySearch(al,"c"));

    ——Collections 替换和反转

        替换:
            replaceAll(List,oldVal,newVal)
                将新值替换旧值。

        ArrayList<String> al = new ArrayList<String>();
    al.add("ass");
    al.add("kkk");
    al.add("ww");
    al.add("hhhhh");
    al.add("ww");
    al.add("jjjj");
    System.out.println("修改前:" + al);
     
    Collections.replaceAll(al, "ww", "cccc");
    System.out.println("替换后:" + al);

        反转:
            reverse(List)
                将List集合元素反转。
            Comparator reverseOrder()
                该方法返回一个比较器,将集合的compare强行逆序。
                (将List逆序排序)
                可以将该方法直接放到TreeSet中,也可以在该方法中传入自定义比较器,将自定义比较器顺序强行逆序。

    ——Collections synchronizedList
            传入一个List集合,返回一个同步的List集合。 
            将List传入synchronizedList之后,SynchronizedList类会对其进行加锁,从而达到同步的目的。 
            也可以对Set、Map进行加锁操作。

    ——Collections swap
            reverse方法底层就是swap方法。
             static void swao(List,int i,int j)
             交换 i 脚标和 j 脚标的元素。 

    ——Collections shuffle
            public static voi shuffle(List list)
            对列表顺序进行随机置换。 

    ——Arrays
            用于操作数组的工具类,里面都是静态方法。 
     
    ——System类
     
        描述系统的一些信息。 
        System类没有构造函数,不能创建对象。
        System类方法都是静态的:
            out:标准输出,默认控制台。
            in:  标准输入,默认键盘。
        
        
        方法:
            static long currentTimeMillis()
                返回以毫秒为单位的当前时间。
            void gc()
                垃圾回收器。
            String setProperties(String key,String value)
                设置系统属性信息。
            Properties getProperties();
                获取系统属性信息。 
                获取的是虚拟机在启动时加载的一些默认的系统属性信息。
                public static void main(String[] args)
                {
                    //因为Properties是Hashtable的子类,也就是Map集合的一个子类对象
                    //那么可以通过Map集合的方法取出该集合中的元素。
                    Properties prop = System.getProperties();
                    for(Object obj:prop.keySet())
                    {
                        System.out.println(obj+ " -- " + prop.get(obj));
                    }
                }
            在JVM启动时动态加载一些系统属性信息:
                java -D name=value lei

        跨平台性:
            System.get("os.name");
                该方法可以跨平台,根据操作系统不同输出结果也不同。 
                根据此方法可以判断不同平台的不同操作。 

    ——Runtime
        
            每个Java应用程序都有一个Runtime类的实例对象,使应用能够与其运行的环境相连接,可以通过getRuntime()方法获取当前运行
            时对象。

            Runtime类无构造函数,不能直接创建对象,但是却有非静态方法,说明该类肯定提供了一个方法获取本类对象,而且该方法是静
            态的,并且返回值类型是本类类型。 
                static Runtime getRuntime()
                    返回与当前Java应用程序相关的运行时对象,这个对象随着JVM的启动而产生。
                    该方法使用了单例设计模式,保证了对象的唯一性。
                Process exec(String command)
                    根据传入的字符串命令执行,相当于在DOS中执行命令。
                    (可以使用循环写出小病毒)
                    Runtime r = Runtime.getRuntime();
                        r.exec("notepad.exe ***.txt");
                        该语句可以将txt文件复制到一个新的文本文档中,并且只要与其运行程序相关联的文件都可以打开,比如播放器和电影文件

                Process类中又一个void destory()方法,可以杀掉子进程,但是destory方法只能结束被Runtime对象启动的方法,因为对于系统
                进程无法获取其启动对象,所以无法结束。
                    Runtime r = Runtime.getRuntime();
                    Process p = r.exec("D:\360.exe");
                    Thread.sleep(4000);    //使当前线程等待四秒
                    p.destory();    //杀掉子进程
     

    ——反射

        JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的
        任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。

        应用在一些通用性比较高的代码中。
        后面学到的框架,大多数都是使用反射来实现的。
        在框架开发中,都是基于配置文件来开发的。
            在配置文件中配置了类的相关路径,它(框架)就可以使用反射机制来得到类中的所有内容,也可以执行类中的某个方法。
            类中的所有内容:属性,无参构造,有参构造,普通方法。
        分析反射的原理:
            第一步:创建Java文件
            第二步:编译Java文件,生成class文件。
            第三步:通过虚拟机加载类(class)文件,会在内存中生成一个Class类,来表示.class字节码文件。
                       如果得到了Class类,就可以得到这个类中的所有内容,包括:属性,构造方法,普通方法。
            所以:如果想要使用反射机制,首先需要得到Class类。
                得到Class类的三种方式:
                    类名.class
                    对象.getClass()
                    使用Class.forName(:路径“)
                属性的表示类:Field
                构造方法表示类:Constructor
                普通方法表示类:Method

            那么得到Class类之后,怎么对属性,构造方法和普通方法进行操作呢。
                1、首先获取Class类。
                    Class class1 = Person.class;
                    Class class2 = new Person().getClass();
                    Class class3 = Class.forName("包名.类名");
                2、面试题
                    对一个类进行实例化,可以new,那么如果不使用new,怎么获取对象?
                    答:可以使用反射机制来获取对象。
                        //首先获取Class 类的实例
                        Class c = Class.forName("完整类路径");
                        //得到某个类的实例
                        Person p = (Person) c.newInstance();
                    1)操作无参构造的代码
                        //得到Class
                        Class c - Class.forName("完整类路径");
                        //得到Person类的实例
                        Person p = (Person)c.newInstance();
                        //操作对象
                        p.setName("张三");
                        //输出值
                        System.out.println(p.getName());

                    2)操作有参构造方法的代码
                        import java.lang.reflect.Constructor;
                        //得到Class
                        Class c = Class.forName("完整类名");
                        //使用有参数的构造方法
                        //c.getConstructors();//获取所有的构造方法
                        //getConstructor()方法传递的参数是有参构造方法里面的参数类型,类型使用class形式进行传递,例如String.class,int.class
                        Constructor cs = c.getConstructor(String.class,int,class);
                        //通过有参数的构造方法设置值。
                        //通过有参数的构造方法来创建Person实例,并设置初始值
                        Person p = (Person)cs.newInstance("张三",20);
                        //输出
                        System.out.println(p.getName() + "  " + p.getAge());

                    3)使用反射操作属性
                        import java.lang.reflect.Field;
                        //得到Class类实例
                        Class c = Class.forName("完整类名");
                        //得到Person类的实例
                        Person p = (Person)c.newInstance();
                        //c,getDeclaredFields(); //表示得到所有的属性
                        //得到name属性
                        Field f = c.getDeclaredField("name"); 
                        //操作的是私有的属性,默认不允许操作,需要通过setAccessible方法来设置可以操作私有属性。
                        f.setAccessible(true);
                        //设置name值,使用set方法传入两个参数,第一个参数是类的实例,第二个参数是需要设置的属性。
                        f.set(p,"李四");    //相当于p.name = "李四";
                        //获取name的值
                        System.out.println(f.get(p));    //相当于p.name

                    4)使用反射操作成员方法
                        使用Method类表示普通方法
                        //得到Class类的实例
                        Class c = Class.forName("完整类名");
                        //得到Person类实例
                        Person p = (Person)c.newInstance();
                        //得到普通方法
                        //c.getDeclareMethods();    //得到所有的普通方法
                        //getDeclareMethod()方法需要传递两个参数,第一个参数是方法名,第二个参数是参数类型。
                        Method  = c.getDeclareMethod("setName",String.class);
                        //执行setName方法:传递两个参数,第一个参数是Person类的实例,第二个参数为该方法的参数值。
                        //执行了invoke方法后,相当于执行了setName方法,同时传入的参数为“王五”
                        m.invoke(p,"王五");
                        //输出
                        System.out.println(p.getName());
                    如果操作的是私有方法,需要:
                        m.setAccessible(true);
                        当操作的方法是静态方法时,不需要使用反射,因为静态方法可以直接使用类名调用,不需要类的实例。
                        使用反射操作静态的时候,也不需要实例,在invoke方法传参的时候传入一个null即可。
                            m.invoke(null,"王五");

            反射应用:
                在Web项目中的web.xml文件中,可以根据servlet-class的Servlet路径来找到对应的servlet实例,从而操作方法或
                者属性,这也就是框架的底层机制。

  • 相关阅读:
    PyQt(Python+Qt)学习随笔:QDial刻度盘部件功能简介
    PyQt(Python+Qt)学习随笔:QSlider滑动条部件功能简介
    PyQt(Python+Qt)学习随笔:QScrollBar以及QAbstractSlider滚动条部件功能详解
    第15.43节、PyQt输入部件:QAbstractSpinBox派生类QSpinBox、 QDoubleSpinBox、QDateTimeEdit、QDateEdit和QTimeEdit功能简介
    第三十六章、PyQt输入部件:QAbstractSpinBox派生类QSpinBox、 QDoubleSpinBox、QDateTimeEdit、QDateEdit和QTimeEdit
    PyQt(Python+Qt)学习随笔:QDateEdit日期编辑部件和QTimeEdit时间编辑部件
    程序员求职之道(《程序员面试笔试宝典》)之面试官箴言?
    程序员求职之道(《程序员面试笔试宝典》)之面试心得交流?
    程序员求职之道(《程序员面试笔试宝典》)之企业面试笔试攻略(互联网)?
    程序员求职之道(《程序员面试笔试宝典》)之面试笔试技巧?
  • 原文地址:https://www.cnblogs.com/wwwwyc/p/6375025.html
Copyright © 2011-2022 走看看