zoukankan      html  css  js  c++  java
  • 《Thinking in Java》学习笔记(三)

    1>Java中的常量

      使用final和static来修饰的变量称为常量,常量用大写字母表示,字母间用下划线连接。

      Java中定义常量有以下几种方式:

    interface ConstantInterface {  
        String SUNDAY = "SUNDAY";  
        String MONDAY = "MONDAY";  
        String TUESDAY = "TUESDAY";  
        String WEDNESDAY = "WEDNESDAY";  
        String THURSDAY = "THURSDAY";  
        String FRIDAY = "FRIDAY";  
        String SATURDAY = "SATURDAY";  
    }  
    enum ConstantEnum {  
        SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY  
    }  
    class ConstantClassField {  
        public static final String SUNDAY = "SUNDAY";  
        public static final String MONDAY = "MONDAY";  
        public static final String TUESDAY = "TUESDAY";  
        public static final String WEDNESDAY = "WEDNESDAY";  
        public static final String THURSDAY = "THURSDAY";  
        public static final String FRIDAY = "FRIDAY";  
        public static final String SATURDAY = "SATURDAY";  
    } 

      第一种方式利用了接口(Interface)的中变量默认为static final的特性,但是不符合接口设计的初衷。

      第三种方式如果静态变量很多时,如果我们只需要其中的一个常量,导致的结果却是整个类被加载到内存中,这点是需要注意的,特别是类中的常量很多时。

    2>容器类的并发性

      HashMap不是线程安全的,在并发的情况下可能会引起CPU占用率100%的情况,这是需要注意的。

      HashSet底层也是用HashMap实现的,也是线程不安全的。

      TreeMap和TreeSet也不是线程安全的。

      解决办法有2种:

      一是使用线程安全的版本,例如HashMap对应的ConcurrentHashMap,HashSet对应的CopyOnWriteArraySet。

      二是使用Collections的静态方法,例如Collections.synchronizeMap()。

      ArrayList也不是线程安全的,多线程的情况下可以使用CopyOnWriteArrayList或者Vector来代替。CopyOnWriteXXX类读时不加锁,写入时会加锁。

      还有我们常用的StringBuffer是线程安全的,StringBuilder不是线程安全的。

    3>异常和错误

      Throwable是Java处理错误的父类。

      Throwable的子类可以分为2类:Error和Exception。

      Error是JVM无法预期的错误,将会导致程序的崩溃,无法修复,例如内存溢出OutOfMemoryError。

      Exception是可以恢复的意外,是可以被捕获到的,可以被修复的。

      出现异常后,系统会把异常一直往上抛,没有处理的代码,就会一直往上抛。最终的结果是,单线程由main方法抛出,多线程的由Thread.run()抛出。

      我们使用try/catch来捕获并处理异常,就是希望程序不会意外的终止。

      Java提供了2种异常机制:

      1.运行时异常,RuntimeException,出现异常时交由虚拟机去处理。

      2.检查式异常,编译器强行要求我们处理的异常,常见的包括I/O异常,sql异常,我们必须用try/catch来捕获并处理异常,否则无法通过编译。

      常见的运行时异常包括:ClassCastException,DOMException,NullPointerException,IndexOutOfBoundException(数组越界)。

      随着程序的调试,运行时异常会越来越少,程序健壮性也会越来越好。

    4>接口

      接口的修饰符可以有public和缺省的2种。

      接口中的域默认的是public和final的,即使不去写public和final,它们也是public和final的。

      接口中方法默认的是public的,即使不去写public,它们也是public的。

      

      当一个类继承自一个类又实现了接口时,继承必须被放在前面,否则会报错。

      接口也可以继承自一个或者多个接口:interface A extends B,C。B和C是接口。

      接口可以嵌套在其他的接口或者类中,如下:

      

      接口的修饰符可以有public和缺省的2种,所以会报上面的错误。

      

    public interface IA { 
        public void out();
        
    }
    public class SA { 
        public void out() {
            System.out.println("SA");
        }
    
    }
    public class A extends SA implements IA{  
        public static void main(String[] args) {
            new A().out();
        }
    
    }

      输出的结果是:SA
      接口中的方法在实现类中都要写出来,A中里却没有,这是因为父类实现了这个方法。所以这里调用的还是父类的方法。

    5>内部类

      内部类可以是静态static的,也可用public,default,protected和private修饰。而普通类只能使用public和default。

      内部类按使用的场景可以分为以下几种情况:

      1.成员内部类

      就是作为外部类的成员,可以直接使用外部类的所有成员和方法,即使是private的。同时外部类要访问内部类的所有成员变量/方法,则需要通过内部类的对象来获取。

      成员内部类不能含有static的变量和方法。因为成员内部类需要先创建了外部类,才能创建它自己。

    public class Outer {    
         public static void main(String[] args) {        
            Outer outer = new Outer();         
            Outer.Inner inner = outer.new Inner();       //注意用法  
            inner.print("Outer.new");          
         }   
      
          public class Inner {       
              public void print(String str) {            
                 System.out.println(str);       
              }  
                
              public Outer getOuterInstance(){
                    return Outer.this;         //注意用法
            }
       } 
    } 

      2.局部内部类

      局部内部类,是指内部类定义在方法和作用域内。

    public class Parcel4 {    
         public Destination destination(String s) {        
             class PDestination implements Destination {           
                  private String label;              
                  private PDestination(String whereTo) {                
                         label = whereTo;         
                }              
                public String readLabel() {                
                         return label;            
                 }       
              }       
              return new PDestination(s);     
        }      
        public static void main(String[] args) {       
          Parcel4 p = new Parcel4();         
          Destination d = p.destination("Tasmania");   
      } 
    }

      局部内部类也像别的类一样进行编译,但只是作用域不同而已,只在该方法或条件的作用域内才能使用,退出这些作用域后无法引用的。

    3.嵌套内部类

      嵌套内部类,就是修饰为static的内部类。声明为static的内部类,不需要内部类对象和外部类对象之间的联系,就是说我们可以直接引用outer.inner,即不需要创建外部类,也不需要创建内部类。

      嵌套类和普通的内部类还有一个区别:普通内部类不能有static数据和static属性,也不能包含嵌套类,但嵌套类可以。

      严格地讲,嵌套内部类不属于内部类,没有外部类对象时,也能够访问嵌套内部类。

    public class StaticTest {   
          private static String name = "javaJohn";           
        private String id = "X001";  
        static class Person{  
          private String address = "swjtu,chenDu,China";  
          public String mail = "josserchai@yahoo.com";//内部类公有成员   
          public void display(){  
            //System.out.println(id);//不能直接访问外部类的非静态成员   
            System.out.println(name);//只能直接访问外部类的静态成员   
            System.out.println("Inner "+address);//访问本内部类成员。   
          }  
        }  
        
        public void printInfo(){  
          Person person = new Person();  
          person.display();  
          //System.out.println(mail);//不可访问   
          //System.out.println(address);//不可访问   
          System.out.println(person.address);//可以访问内部类的私有成员   
          System.out.println(person.mail);//可以访问内部类的公有成员   
        
        }  
        public static void main(String[] args) {  
        StaticTest staticTest = new StaticTest();  
        staticTest.printInfo();  
      }  
     }  

    4.匿名内部类

      使用匿名内部类还有个前提条件:必须继承自一个抽象类或实现一个接口。

    interface Person {
        public void eat();
    }
     
    
    public class Demo {
        public static void main(String[] args) {
            Person p = new Person() {
                public void eat() {
                    System.out.println("eat something");
                }
            };
            p.eat();
       }
    }

      内部类的继承

      内部类的继承,是指内部类被继承,普通类 extents 内部类。而这时候代码上要有点特别处理。

    public class InheritInner extends WithInner.Inner {      
        // InheritInner() 是不能通过编译的,一定要加上形参     
      InheritInner(WithInner wi) {        
             wi.super();    
         } 
         
        public static void main(String[] args) {       
            WithInner wi = new WithInner();         
            InheritInner obj = new InheritInner(wi);     
         }
     }
      
    class WithInner {    
         class Inner {      } 
    } 

      可以看到子类的构造函数里面要使用父类的外部类对象.super();而这个对象需要从外面创建并传给形参。

      内部类还有一些需要注意的地方,如下:

      1.嵌套类是可以放到接口中,默认是static的

    class T2 {
      public void test() {
        IN.MyTestInner ttt = new IN.MyTestInner();
           ttt.testInner();
      }
    }
    
    interface IN {
      public void testOutter();
    
      // 嵌套类
      public class MyTestInner {
        public void testInner() {
          System.out.println("testInner");
        }
      }
    }

      2.每个内部类都可以独立的实现一个接口,无论这个接口是否已经被外部类所实现。

      3.如果是抽象类而不是接口,那么只有内部类才能实现多继承。

      

  • 相关阅读:
    LeetCode 23. 合并K个排序链表
    LeetCode 199. 二叉树的右视图
    LeetCode 560. 和为K的子数组
    LeetCode 1248. 统计「优美子数组」
    LeetCode 200. 岛屿数量
    LeetCode 466. 统计重复个数
    LeetCode 11. 盛最多水的容器
    LeetCode 55. 跳跃游戏
    LeetCode 56. 合并区间
    Java生鲜电商平台-订单架构实战
  • 原文地址:https://www.cnblogs.com/lnlvinso/p/4364329.html
Copyright © 2011-2022 走看看