• Java学习笔记(二)


    1. Java抽象类:
    • 抽象类和抽象方法都必须用abstract修饰,而且抽象方法不能有方法体
    • 抽象类不能被实例化,即便这个抽象类没有包含抽象方法
    • 抽象类的构造器不能用于创建实例,只能用于被其子类调用
    • 含有抽象方法的类(包括直接定义一个抽象方法;继承了一个抽象父类但没有完全实现父类包含的抽象方法;以及实现了一个接口,但没有完全实现接口包含的抽象方法三种情况)只能被定义为抽象类
    • 注意:
      • abstract修饰的方法只能被子类复写并实现,而final修饰的方法不允许子类复写,故abstract和final永远不要一起使用
      • abstract不能用于修饰属性和局部变量,也不能用于修饰构造器
    • abstract也不能与private同时使用(private修饰的变量不会被子类重写)
    2. 局部内部类、变量只在方法内有效,它的上一级程序单元是方法而不是类,故不能用static和访问控制权限符修饰

    3. HashSet:
    •  1 import java.util.*;
       2 
       3 //A类的equals方法总是返回ture,但没有重写切hashCode方法
       4 class A{
       5     public boolean equals(Object obj){
       6         return true;
       7     }
       8 }
       9 
      10 //B类的hashCode方法总是返回1,但没有重写其equals方法
      11 class B{
      12     public int hashCode(){
      13         return 1;
      14     }
      15 }
      16 
      17 //C类的hashCode总是返回2,有重写其equals方法
      18 class C{
      19     public int hashCode(){
      20         return 2;
      21     }
      22 
      23     public boolean equals(Object obj){
      24         return true;
      25     }
      26 }
      27 
      28 public class TestSet 
      29 {
      30     public static void main(String[] args) 
      31     {
      32         HashSet books = new HashSet();
      33         books.add(new A());
      34         books.add(new A());
      35         books.add(new B());
      36         books.add(new B());
      37         books.add(new C());
      38         books.add(new C());
      39         System.out.println(books);
      40     }
      41 }
      42 
      43 
      44 /*
      45 [B@1, B@1, C@2, A@2a139a55, A@15db9742]
      46 请按任意键继续. . . 
      47 */
    • HashSet通过同时判断equals和hashCode来区别重复元素(如果equals和hashCode对比返回都是true, 则为重复元素)
    • HashSet储存是无序的,是根据hashCode的值来对应一个储存位置来存储元素(其实hashCode就相当于HashSet的索引,它通过这个索引来找到对应元素,速度很快)
    • 重写hashCode的规则:
      • 当两个对象通过equals方法比较返回true时,这两个对象的hashCode的值应该相等
      • 对象中用作equals比较标准的属性,都应该用来计算hashCode的值
    • 向HashSet中添加一个个可变对象,并改变其值可能会产生的问题:
      •  1 import java.util.*;
         2 class R
         3 {
         4     int count;
         5     public R(int count){
         6         this.count = count;
         7     }
         8 
         9     public String toString(){
        10         return "R(count 属性 :" + count + " )";
        11     }
        12 
        13     public boolean equals(Object obj){
        14         if(obj instanceof R){
        15             R r = (R)obj;
        16             if(r.count == this.count){
        17                 return true;
        18             }
        19         }
        20         return false;
        21     }
        22 
        23     public int hashCode(){
        24         return this.count;
        25     }
        26 }
        27 
        28 
        29 public class TestHashSet 
        30 {
        31     public static void main(String[] args) 
        32     {
        33         HashSet hs = new HashSet();
        34         hs.add(new R(5));
        35         hs.add(new R(-3));
        36         hs.add(new R(9));
        37         hs.add(new R(253));
        38 
        39         //打印HashSet集合
        40         System.out.println(hs);
        41 
        42         //取出第一个元素
        43         Iterator it = hs.iterator();
        44         it.next();
        45         R first = (R)it.next();
        46         //为第一个元素的count赋值
        47         first.count = -3;
        48 
        49         //再次输出HashSet集合,集合有重复元素
        50         System.out.println(hs);
        51 
        52         //删除count为-3的R对象
        53         hs.remove(new R(-3));
        54 
        55         //可以看到被删除了一个R元素
        56         System.out.println(hs);
        57 
        58         //输出false
        59         System.out.println("hs是否包含count为-3的R对象?" + hs.contains(new R(-3)));
        60         //输出false
        61         System.out.println("hs是否包含count为5的R对象?" + hs.contains(new R(5)));
        62     }
        63 }
        64 
        65 /*
        66 [R(count 属性 :-3 ), R(count 属性 :5 ), R(count 属性 :9 ), R(count 属性 :253 )]
        67 [R(count 属性 :-3 ), R(count 属性 :-3 ), R(count 属性 :9 ), R(count 属性 :253 )]
        68 [R(count 属性 :-3 ), R(count 属性 :9 ), R(count 属性 :253 )]
        69 hs是否包含count为-3的R对象?false
        70 hs是否包含count为5的R对象?false
        71 请按任意键继续. . .    
        72 */
      • 说明:
        • 第二个-3虽然值为-3,但它却是放在原来值为-5的位置,删除时不会被删除,而且这个时候equals和hashCode永远不能保持一致,之后这个HashSet的访问将会存在问题
      • 注意:当向HashSet中添加可变对象时,必须十分小心,如果修改HashSet集合中的对象,有可能导致该对象与集合中的其他对象相等,从而导致HashSet无法准确访问该对象

    4. TreeSet(是SortedSet接口的唯一实现)
    • 自然排序:Java提供了一个Comparable接口,该接口里定义了一个compareTo(Object obj)方法,实现了该接口就可以比较大小,常见类已经实现了该方法,TreeSet根据该方法来进行排序
    • 如果试图将一个对象添加进TreeSet,则该对象的类必须实现Comparable接口,否则程序将会抛出异常(向TreeSet里添加对象时,只有第一个元素可以不实现Comparable接口,但这不是一个好做法,当取出该元素是会抛出ClassCastException)
    • 向TreeSet里添加的也应该是同一类型的对象,否则也会抛出ClassCastException(实现compareTo(Object obj)方法时也应该将obj强制转换为相同类型来进行比较)
    • 判断重复元素的标准:
      • equals方法返回true
      • compareTo方法返回0
    • 如果两个对象的equals方法返回true,则应该保证compareTo方法返回0;

    5. LinkedList
    •  1 import java.util.*;
       2 
       3 public class TestLinkedList  
       4 {
       5     public static void main(String[] args) 
       6     {
       7         LinkedList books = new LinkedList();
       8         //将字符串元素加入队列的尾部
       9         books.offer("Robbin1");
      10         //将一个字符串元素入栈
      11         books.push("Robbin2");
      12         //将字符串元素添加到队列的头部
      13         books.offerFirst("Robbin3");
      14         for(int i = 0; i < books.size(); i++){
      15             System.out.println(books.get(i));
      16         }
      17 
      18         //访问并不删除队列的第一个元素
      19         System.out.println(books.peekFirst());
      20         //访问并不删除队列的最后一个元素
      21         System.out.println(books.peekLast());
      22         //采用出栈的方式将第一个元素pop出队列
      23         System.out.println(books.pop());
      24         //下面输出将看到第一个元素被删除
      25         System.out.println(books);
      26         //访问并删除队列的最后一个元素
      27         System.out.println(books.pollLast());
      28         System.out.println(books);
      29     }
      30 }
      31 
      32 /*
      33 Robbin3
      34 Robbin2
      35 Robbin1
      36 Robbin3
      37 Robbin1
      38 Robbin3
      39 [Robbin2, Robbin1]
      40 Robbin1
      41 [Robbin2]
      42 请按任意键继续. . .
      43 */
    • LinkedList兼备List,stack和双向队列的功能,一般与ArrayList没有太大性能上的差异,但在一些性能敏感的地方要注意选择
    • 关于List集合的建议:
      • 如果需要遍历List集合元素,对于ArrayList和vector集合,则应该使用随机访问方法(get)来遍历集合元素,这样性能更好。对于LinkedList集合,则应该采用迭代器(Iterator)来遍历集合元素;
      • 如果需要经常执行插入、删除操作来改变List集合的大小,则应该使用LinkedList集合而不是ArrayList。使用ArrayList、vector集合将需要重新分配内部数组大小,其时间开销常常是使用LinkedList的时间开销的几十倍,效果更差;
      • 如果有多条线程同时访问List集合中的元素,可以考录vector这个同步实现;
     
     

    6. 操作集合的工具类

    排序操作:

      •  1 import java.util.*;
         2 public class TestSort 
         3 {
         4     public static void main(String[] args) 
         5     {
         6         ArrayList nums = new ArrayList();
         7         nums.add(2);
         8         nums.add(-5);
         9         nums.add(3);
        10         nums.add(0);
        11         nums.add(1);
        12 
        13         System.out.println(nums);
        14         //将List集合元素的次序反转
        15         Collections.reverse(nums);
        16         System.out.println(nums);
        17         //将List集合元素按自然排序排序
        18         Collections.sort(nums);
        19         System.out.println(nums);
        20         //将List集合元素按随机顺序排序
        21         Collections.shuffle(nums);
        22         //每次输出的次序不固定
        23         System.out.println(nums);
        24 
        25     }
        26 }
        27 
        28 /*
        29 输出结果:[2, -5, 3, 0, 1]
        30 [1, 0, 3, -5, 2]
        31 [-5, 0, 1, 2, 3]
        32 [2, 1, 0, 3, -5]
        33 请按任意键继续. . .
        34 */
      •   1 import java.util.*;
          2 import java.lang.reflect.Array;
          3 public class ShowHand 
          4 {
          5     //定义该游戏最多支持几个玩家
          6     private final int PLAY_NUM = 5;
          7     //定义扑克牌的所有花色
          8     //下面是四个特殊字符,会在控制台打印出方块,草花, 红心,黑桃
          9     private String[] types = {"4 ", "5 ", "3 ", "6 "};
         10     private String[] values = {"2 ", "3 ", "4 ", "5 ", "6 ", "7 ", "8 ", "9 ", "10 ", "J ", "Q ", "K ", "A "};
         11 
         12     //cards是一局游戏中剩下的扑克牌
         13     private List<String> cards = new LinkedList<String>();
         14     //定义所有玩家
         15     private String[] players = new String[PLAY_NUM];
         16     //所有玩家手上的扑克牌
         17     private List<String>[] playersCards = new List[PLAY_NUM];
         18 
         19     /**
         20     * 初始化扑克牌,放入52张扑克牌,并且使用shuffle方法将他们按随机顺序排序
         21     */
         22     public void initCards(){
         23         for(int i = 0; i < types.length; i++){
         24             for(int j = 0; j < values.length; j++){
         25                 cards.add(types[i] + values[j]);
         26             }
         27         }
         28         //随机排序
         29         Collections.shuffle(cards);
         30 
         31     }
         32 
         33 
         34     /**
         35     * 初始化玩家,为每个玩家分配用户名
         36     */
         37     public void initPlayer(String... names){
         38         if(names.length > PLAY_NUM || names.length < 2){
         39             //校检玩家数量,此时处理异常更合理
         40             System.out.println("玩家数量不对");
         41             return ;
         42         }else{
         43             //初始化玩家用户名
         44             for(int i = 0; i < names.length; i++){
         45                 players[i] = names[i];
         46             }
         47         }
         48     }
         49 
         50     /**
         51     * 初始化玩家手上的扑克牌,开始游戏时每个玩家手上的扑克牌为空,
         52     * 程序使用一个长度为0的LinkedList表示。
         53     */
         54     public void initPlayerCards(){
         55         for(int i = 0; i < players.length; i++){
         56             if(players[i] != null && !players[i].equals("")){
         57                 playersCards[i] = new LinkedList<String>();
         58             }
         59         }
         60     }
         61 
         62     /**
         63     * 输出全部扑克牌,该方法没有实际作用,仅用作测试
         64     */
         65     public void showAllCards(){
         66         for(String card : cards){
         67             System.out.println(card);
         68         }
         69     }
         70 
         71     /**
         72     * 派扑克牌
         73     * @param first 最先派给谁
         74     */
         75     public void deliverCard(String first){
         76         //调用ArrayUtils工具类的search方法。查询出制定元素在数组中的索引
         77         //int firstPos = ArrayUtils.search(players, first);
         78         int firstPos = 0;
         79         //依次给位于该指定玩家之后的每个玩家派扑克牌
         80         for(int i = firstPos; i < PLAY_NUM; i++){
         81             if(players[i] != null){
         82                 playersCards[i].add(cards.get(0));
         83                 cards.remove(0);
         84             }
         85         }
         86         //依次给位于该指定玩家之前的每个玩家派扑克牌
         87         for(int i = 0; i < firstPos; i++){
         88             if(players[i] != null){
         89                 playersCards[i].add(cards.get(0));
         90                 cards.remove(0);
         91             }
         92         }
         93     }
         94 
         95     /**
         96     * 输出玩家手上的扑克牌
         97     * 实现该方法时,应该控制每个玩家看不到别人的第一张牌, 但此处没有增加该功能
         98     */
         99     public void showPlayerCards(){
        100         for(int i = 0; i < PLAY_NUM; i++){
        101             //当玩家不为空时
        102             if(players[i] != null){
        103                 System.out.print(players[i] + " : ");
        104                 //便利玩家手上的牌
        105                 for(String card : playersCards[i]){
        106                     System.out.print(card + "	");
        107                 }
        108                 System.out.print("
        ");
        109             }
        110         }
        111     }
        112     public static void main(String[] args) 
        113     {
        114         ShowHand sh = new ShowHand();
        115         sh.initPlayer("电脑玩家", "ME");
        116         sh.initCards();
        117         sh.initPlayerCards();
        118         //下面测试所有扑克牌,没有实际作用
        119         sh.showAllCards();
        120         System.out.println("---------------------------------------------------------------------");
        121         //下面从ME开始派牌
        122         sh.deliverCard("ME");
        123         sh.showPlayerCards();
        124 
        125         sh.deliverCard("电脑玩家");
        126         sh.showPlayerCards();
        127     }
        128 }
        129 
        130 
        131 /*
        132  5
        133  2
        134  9
        135  6
        136  K
        137  K
        138  8
        139  7
        140  6
        141  8
        142  4
        143  6
        144  8
        145  A
        146  2
        147  2
        148  4
        149  3
        150  3
        151  J
        152  9
        153  A
        154  7
        155  10
        156  3
        157  Q
        158  6
        159  Q
        160  J
        161  9
        162  4
        163  A
        164  5
        165  4
        166  10
        167  K
        168  10
        169  8
        170  9
        171  10
        172  7
        173  Q
        174  A
        175  K
        176  J
        177  2
        178  5
        179  7
        180  Q
        181  5
        182  3
        183  J 
        184 ---------------------------------------------------------------------
        185 电脑玩家 :  5
        186 ME :  2
        187 电脑玩家 :  5   9
        188 ME:  2         6
        189 请按任意键继续. . .    
        190 */
      • 查找替换操作:
        • static int binarySearch (List list, Object key):使用二分法搜索指定List集合,以获得指定对象在List集合中的索引(如果该方法要能正常工作,必须保证List集合元素已经处于有序状态)
        • static Object max(Collection coll):更具元素的自然顺序,返回给定集合中的最大元素
        • static Object max(Collection coll, Comparator comp):根据指定Comparator产生的顺序,返回指定集合的最大元素
        • static Object min(Collection coll)
        • static Object min(Collection coll, Comparator comp)
        • static void fill(List list, Object obj):使用指定元素obj替换指定List集合中的所有元素
        • static int frequency(Collection c, Object o):返回指定List集合中的指定对象的元素数量
        • static int indexOfSubList(List source, List target):返回List对象在母List对象中第一次出现的位置索引;如果母List中没有出现这样的子List,则返回-1
        • static int lastIndexOfSubList(List source, List target)
        • static boolean replaceAll(List list, Object oldVal, Object newVal):使用一个新值newVal替换List对象所有的旧值oldVal
        •  1 import java.util.*;
           2 public class TestSearch 
           3 {
           4     public static void main(String[] args) 
           5     {
           6         ArrayList nums = new ArrayList();
           7         nums.add(2);
           8         nums.add(-5);
           9         nums.add(3);
          10         nums.add(0);
          11         
          12         System.out.println(nums);
          13         //输出最大元素,将输出3
          14         System.out.println(Collections.max(nums));
          15         //输出最小元素,将输出-5
          16         System.out.println(Collections.min(nums));
          17         //将nums中的0用1来替代
          18         Collections.replaceAll(nums, 0, 1);
          19         System.out.println(nums);
          20         //判断-5在集合nums中出现的次数,将输出1
          21         System.out.println(Collections.frequency(nums, -5));
          22         //对nums集合排序
          23         Collections.sort(nums);
          24         System.out.println(nums);
          25         //只有排序后的List集合才可用二分法查询,输出3
          26         System.out.println(Collections.binarySearch(nums, 3));
          27     }
          28 }
          29 
          30 /*
          31 [2, -5, 3, 0]
          32 3
          33 -5
          34 [2, -5, 3, 1]
          35 1
          36 [-5, 1, 2, 3]
          37 3
          38 请按任意键继续. . .
          39 
          40 */
      • 同步控制:(Java常用集合框架中推荐使用的三么实现类:HashSet、ArrayList和HashMap都是线程不安全的。如果有多条线程访问它们,而且有超过一条的线程试图改变它们,则可能出现错误。Collections提供了多个静态方法用于创建同步集合)

        •  1 import java.util.*;
           2 public class TestSynchronized 
           3 {
           4     public static void main(String[] args) 
           5     {
           6         //下面程序创建了四个同步集合对象
           7         Collection c = Collections.synchronizedCollection(new ArrayList());
           8         List list = Collections.synchronizedList(new ArrayList());
           9         Set s = Collections.synchronizedSet(new HashSet());
          10         Map m = Collections.synchronizedMap(new HashMap());
          11     }
          12 }
    • 设置不可变集合:

      • emptyXxx()
      • singletonXxx()
      • unmodifiableXxx()
  • 相关阅读:
    mac 使用tree命令
    为什么redis支持lua脚本功能
    redis协议
    Linux的SOCKET编程详解
    大型网站架构之分布式消息队列
    自定义String
    逆转单链表
    单例模式 C++
    构造函数不能为虚函数
    Windows消息机制
  • 原文地址:https://www.cnblogs.com/qjm253/p/5745134.html
Copyright © 2020-2023  润新知