[09]-小而美


數據庫連接池的理解和優化、事物處理

  • Connection類提供事務支持,設置Connection的AutoCommit屬性爲 false,顯式的調用commit()/rollback()
  • 要實現Connection複用,採用每一個事務獨佔一個連接來實現,可大大降低事務管理的複雜性。

新生代-複製清理

  • 新生代分爲三個部分:一個Eden區和兩個Survivor區
  • Eden區存放新生的對象
  • Survivor存放每次垃圾回收後存活的對象
  • 複製算法將可用內存按容量劃分爲大小相等的兩塊,每次只使用其中的一塊。
  • 當這一塊的內存用完了,就將還存活着的對象複製到另外一塊上面,然後再把已使用的內存空間一次清理掉。

linux軟硬鏈接的區別

  • 硬鏈接:文件名B是文件名A的硬鏈接
    • 兩者目錄項的inode節點號相同,都指向同一個文件
    • B和A對於文件系統來說完全平等
    • rm B刪除的是B這個文件名,B對應的文件只又在inode節點鏈接數爲0時纔會被系統回收
  • 軟鏈接: 文件名B是文件名A的軟鏈接
    • 兩者目錄項的inode節點號不同,指向兩塊不同的數據塊
    • B的數據塊存放的是A的路徑名,主從關係
    • rm A,B仍然存在,但指向的是一個無效的鏈接

sql group by

//統計每個部門的高於部門平均收入的人數和部門號
//type_id 團單類型; sale_price每個團單的價格
select count(type_id),type_id from( 
    select t1.type_id from tuan_deal_table t1,
    (select t1.type_id,avg(sale_price) as avg_price from tuan_deal_table group by type_id) t2
    where t1.type_id=t2.type_id and t1.sale_prize>t2.avg_price) as s1 group by type_id;

策略模式

List<T> filter(List<T> list,FilterProcessor fp){
    List<T> ansList=new ArrayList<T>();
    for(T t:list){
        if(fp.process(t)){
            ansList.add(t));
        }
    }
    return ansList;
}
List<Person> result=filter(list,FilterProcessor<Person>(){
    boolean process(Person person){
        if(person.getAge)>30){return true;}
        return false;
    }
});

//函數式編程:Lamda表達式
函數的代碼作爲參數進行傳遞
List<Apple> result=filter(list,(Apple app)->app.getColor().equals("red"));
  • 解決同一類問題時,大部分的處理過程一致
    • 接口FilterProcessor
    • 方法boolean process(T)
  • 使用匿名內部類實現篩選

String轉int:正則判斷

String name="123456";
if(name!=null && !"".equals(name.trim()) && name.matches("[0-9]+")){
    Integer ans=Integer.parseInt(name);
}

電腦訪問一個網頁整個過程

  • DNS:將url解析成目標ip和端口號
  • 應用層HTTP:打開socket連接後,向web服務器發送請求
  • 傳輸層TCP
  • 網絡層OSPF、IP:路由器通過Hello報文與鄰居建立鄰接關係:Dijkstra算法
  • 網絡層/鏈路層ARP:根據IP地址獲取物理地址

Runnable開啓線程:start()

RunnableImp r1=new RunnableImp();
//方法調用,與開啓線程無關
r1.run();

Thread t=new Thread(r1);
//開啓新線程,會執行相應的run()
//在當前線程中運行run()
t.start();


  • start()執行過程:
  • 判斷線程狀態是否爲未啓動
  • 執行native方法,start0()分配棧內存,啓動線程
  • 執行run方法

Spring的bean id重複覆蓋問題

  • id一樣,實現類也一樣,參數值不同
  • 後者直接覆蓋前者
  • allowBeanDefinitionOverriding,默認true

Mybatis

  • #:字符串,對自動傳入的數據加一個雙引號
    • #方式能夠很大程度防止sql注入,能用這個就用
  • $:將傳入的數據直接顯示生成在sql,order by user_id

    • 如果傳入的值是111,那麼解析成sql時的值爲order by user_id
    • 如果傳入的值是id,則解析成的sql爲order by id
    • 一般用於傳入數據庫對象,例如傳入表名.

  • DataSource:工廠模式,創建發生於Mybatis初始化過程中

  • Connection:延遲到執行sql語句時

  • DataSource種類 unpooled、pooled、JNDI

  • 一級緩存:sqlsession級別
    • 操作DB時,構造sqlsession對象,內有hashmap,緩存
    • 一次service中查詢相同的用戶信息,session結束時清空
  • 二級緩存:mapper級別,跨sqlsession
    • 執行兩次service查詢

synchronized

  • 普通方法:防止其他線程訪問該實例的同步方法
  • 靜態方法:鎖住的是這個類

t1線程正在訪問 t2線程想要訪問 能成功嗎
普通:同一個對象,NO obj1.普通() NO
obj1.普通() obj1.靜態() NO
普通:不同的對象,YES obj2.普通() YES
obj1.普通() obj2.靜態() YES
靜態:對於靜態,NO obj1.靜態() NO
obj1.靜態() obj2.靜態() NO
靜態:對於普通,YES obj1.普通() NO
obj1.靜態() obj2.普通() NO

Thread.getName()

  • Thread.currentThread().getName():對當前正在執行的線程對象的引用
  • this.getName():Runnable中不能使用,只能在Thread子類中使用
    • 當前調用這個函數的對象的引用,即爲匿名內部類的thread對象名

web.xml配置節:context-param、listener、filter、servlet

  • context-param:寫哪都行,最先加載
    • 提供應用程序上下文信息的鍵值對
  • listener
    • ContextLoaderListener(僅負責IOC開啓關閉)初始化的上下文
    • RequestContextListener(監聽web服務器的每一次請求)
  • filter(順序要保證)
    • filter:name與class
    • filter-mapping:name與url
  • servlet:DispatcherServlet:負責職責的分派

    <servlet>
        <servlet-name>SpringMVC</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:conf/spring-mvc.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
        <async-supported>true</async-supported>
    </servlet>
    
    <servlet-mapping>
        <servlet-name>SpringMVC</servlet-name>
        <url-pattern>/</url-pattern>
    

Servlet不是單例,只是規範

  • Servlet並不是單例,只是容器讓它只實例化一次,表現出單例的效果
  • Servlet是web容器來控制實例化的,並不是你自己用你編寫的代碼來實例化
  • 即使你自己編寫代碼實例化你的servlet,Web服務器也不會直接調用你的實例化的Servlet對象的。
  • 當客戶端第一次請求Servlet的時候,tomcat會根據web.xml配置文件實例化servlet
  • 當又有一個客戶端訪問該servlet的時候,不會再實例化該servlet,也就是多個線程在使用這個實例
  • 它的生命週期是由Tomcat來維護的

Session

  • 第一次請求,服務器生成session對象,用來存儲該會話相關的數據
  • 響應時在請求頭Set-Cookie,在客戶端cookies中添加session_id
  • 之後進行請求時,每次服務器都會檢測session_id找到對應session對象來識別客戶。

  • 數據結構:map+記錄最後訪問時間(防止存儲失效過多)
  • session會話級別,web應用級別,在該web程序全局可訪問,實現單例的ApplicationContext

同步異步、阻塞非阻塞

  • 同步異步(任務需要依賴另一個任務,等不等他完成)可靠性or性能
  • 阻塞非阻塞(cpu的消耗,當前線程出現慢操作)等待or線程切換
  • IO:應用程序、用戶程序緩存、os內核緩存區、磁盤數據:[直接IO直接訪問磁盤]
  • 網絡IO與磁盤IO不同的是:數據的寫入與讀取需要一個協調的過程
    • client和server都有一個socket實例,每個socket實例有兩個緩衝區
    • 寫入OutputSteam對應的sendQ隊列,sendQ滿了則轉移到另一端的recvQ隊列,
    • 如果recv隊列是滿的,會阻塞write

BIO與AIO

  • 磁盤or網絡IO,一旦發生阻塞,線程會失去CPU的使用權
  • BIO阻塞:每個連接分配一個線程,有的連接啥都沒幹,浪費線程
  • AIO非阻塞:每個請求分配一個線程,連接請求註冊到Selector複用器上
    • Channel通道:等價於Socket,註冊自己感興趣的事情
    • Selector選擇器:輪訓,通過SelectionKey報告哪個Channel已準備好
  • Buffer緩存:通過Channle獲得的IO不是直接IO
  • 直接IO:ByteBuffer.allocateDirector(size)每次創建/釋放都調用System.gc

序列化

  • 父類實現Serializable接口時,子類可被序列化
  • 子類實現Serializable接口時,父類沒有,不報錯,不對父類中的屬性進行序列化
  • 如果序列化的屬性是對象,則這個對象必須實現序列化,否則報錯

IO類、設計模式

  • 適配器:讓兩個接口不兼容的類協同工作
    • 被適配String,適配器String實現Reader接口,持有String引用
  • 裝飾器:通過組合動態擴展對象功能,三明治+火腿+雞蛋
    • InputStream、FilterInputStream、LineNumberInputStream

  • 字節流:InputSteam/OutputStream
    • File、Piped、StringBuffer、Filter(Buffered/LineNumber)
  • 字符流:Reader/Writer

    public static int read(String path){
        File file=new File(path);
        FileReader reader;
        try{
            reader = new FileReader(file);
            BufferedReader bufferReader=new BufferedReader(reader);
            int ans=bufferReader.read()-'0';
            return ans;
        }
        catch (FileNotFoundException e){
            e.printStackTrace();
        }
        catch(IOException e){
            e.printStackTrace();
        }
        return Integer.MAX_VALUE;
    }
    
    public static void write(String path,int temp){
        File file=new File(path);
        FileWriter writer;
        try{
            if(!file.exists()){
                file.createNewFile();
            }
            writer=new FileWriter(file);
            BufferedWriter bufferWriter=new BufferedWriter(writer);
            char ctemp = (char)(temp+'0');
            bufferWriter.write(ctemp);
            bufferWriter.flush();
            bufferWriter.close();
        }
        catch (FileNotFoundException e){
            e.printStackTrace();
        }
        catch(IOException e){
            e.printStackTrace();
        }
    }
    

泛型數組

//運行時,確定數組大小
int size=5;
int []nums=new int[size];
//運行時,更改ArrayList大小
ArrayList list=new ArrayList<>(100);//100個空位置
list.size()//實際元素的數目,trimToSize()去掉預留元素位置

public static void main(String[] args){
    @SuppressWarnings(value={"unused", "rawtypes"})
    List list =new ArrayList();
}

public static Object goodCopyOf(Object obj,int newLen){
    Class c1=obj.getClass();
    if(!c1.isArray()){return null;}
    Class componentType=c1.getComponentType();
    int oldLen=Array.getLength(obj);
    Object ansObj=Array.newInstance(componentType, newLen);
    System.arraycopy(obj,0, ansObj,0,Math.min(oldLen, newLen));
    return ansObj;
}

回調:匿名內部類幹活

  • 背景1:類Worker實現接口InA
  • 背景2:類Worker包括一個對類Mask的引用
  • 背景3:類Mask的方法中,形參爲接口InA
  • 匿名內部類中:Worker作爲一個匿名內部類的存在,包括一個對當前類的引用

ThreadLocal:創建線程的局部變量

  • 創建的線程只能被當前線程訪問,其他線程不能訪問
  • 如想設置默認的get值,需重寫initialValue()
  • 本質:值存於堆上,實際上被創建其的類所持有
  • ThreadLocal的值,放入了當前線程的ThreadLocalMap< ThreadLocal,Value>實例中

     public T get(){
        //ThreadLocal.get():以當前線程爲句柄獲取ThreadLocalMap
        ThreadLocalMap localMap=getMap(Thread.currentThread());
        if(map!=null){ return localMap.getEntry(this);}
        return setInitialValue();
    }   
    
    Thread t1=new Thread(new Runnable()
                {
                    ThreadLocal<String> value=new ThreadLocal<String>();
                    @Override
                    public void run(){
                        super.run();
                        value.set("你好");
                        value.get();
                    }
                }//Thread0結束
        );
    

ThreadLocal不會內存泄漏

  • ThreadLocal在線程處理完仍存活(其值已無用,但不能被GC),會產生內存泄漏
    • 線程池中,線程處理完後仍存活複用,線程的ThreadLocalMap與gc roots相連
    • ThreadLocalMap的key爲ThreadLocal,TheadLocal與gc roots相連,強引用阻礙了垃圾回收
  • 不會產生內存泄漏,因爲ThreadLocalMap並不直接用ThreadLocal爲key,而是他的弱引用
    • 使用弱引用,垃圾回收幫你決定何時回收ThreadLocal
    • WeakHashMap:key爲垃圾時,自動移除條目

四種引用

  • 強引用:從不被GC,jvm停止運行時終止
  • 軟引用:內存不足時會被GC
  • 弱引用:GC時一定被弄回收
  • 虛引用:任何時刻都可能被GC
    • 不能用get()獲取真實對象,對象唄回收之後,纔會加入引用隊列

泛型

Father father=new Son(); 
Mother mother=(Mother)father;
  • 背景:向下轉型存在很大的風險:Object->String或Integer,在編譯期不能被發現
  • jdk1.5推出泛型(參數化類型):在使用時指明具體類型,因此不需要向下轉型

  • static方法,無法訪問泛型類的類型參數,若需使用泛型,使其成爲泛型方法
  • 上界:extends Father 只接受Father及其子類
  • 下界:super Son 只接受Son及其父類

  • 使用上界類進行編譯,泛型的特徵被抹去
  • 使用泛型類的對象時,能表現出強類型的特徵:無法向ArrayList.add(Integer)
  • 原因:編譯器在使用泛型類的時候進行預處理轉義,將泛型引用的對象強制轉換爲泛型參數指定的類型,然後再進行真行的編譯,生成Class
  • 效果:從使用上看,帶參的泛型可當做強類型使用,如有不正確的類型操作,編譯期報錯。

http和https的區別

  • https是用SSL安全套接層加密的,Web服務器啓用SSL需要獲得一個服務器證書並將該證書與要使用SSL的服務器綁定,HTTPS使用端口443,而不是象HTTP那樣使用端口80和TCP/IP進行通信

StringBuilder指定初始化容量的大小

StringBuilder sbuilder=new StringBuilder(word.length*10)
  • 運行時進行內存的申請,不會限制只是常量

安全失敗、快速失敗


迭代器for:快速失敗

public class Test{
    public static void main(String[] args){
        String []word=new String [50];
        List<String>bookList=new ArrayList<String>();
        for(int i=0;i<5;i++){
            books.add(String.valueOf(i));
        }
        for(String ele:books){
            System.out.println(ele);
            books.remove(ele);
        }
    }
}

編碼:通過Unicode編碼轉換

  • UTF-8 國際編碼,英文1B,中文3B
  • GBK 國際標準,中英文都2B

String charset="utf-8";
FileOutputSteam outputStream=new FileOutputSream("文件名");
OutputSteamerWriter writer=new OutputStreamWriter(outputSteam,charset);

String str = "字符串";
try{
    byte[] bNums = str.getBytes("utf-8");
    String newStr = new String(temp, "gbk");
} 
catch (UnsupportedEncodingException e){
    e.printStackTrace();
}

連接jdbc

  • 1)加載數據庫驅動程序,自己先下載jarClass.forName(“com.mysql.jdbc.Driver”);
  • 2)提供JDBC連接的URL 協議:子協議:數據源標識
    • jdbc:mysql://localhost:3306/數據庫名字?useUnicode=true&characterEncoding=gbk;
  • 3)創建數據庫的連接
    • DriverManager.getConnection(url,username, password);
  • 4)創建一個Statement靜態sql語句,PreparedStatement動態sql語句,CallableStatement存儲過程
  • 5)執行:executeQuery、executeUpdate、execute

  • 6)處理執行結果,ResultSet行號從1開始,更新返回更新行數

  • 7)關閉jdbc連接:Connection、Statement、ResultSet

public class TestSql{
    public static void main(String[] args){
        try{
             Class.forName("com.mysql.jdbc.Driver").newInstance();
        }
        catch (InstantiationException e1){
            e1.printStackTrace();
        } 
        catch (IllegalAccessException e1){
            e1.printStackTrace();
        } 
        catch (ClassNotFoundException e1){
            e1.printStackTrace();
        } 
        String url="jdbc:mysql://localhost:3306/anyguide2?
            useUnicode=true&characterEncoding=utf-8";
        try{
            Connection connection = DriverManager.getConnection(url, "root", "mhealth365");
            Statement statement = connection.createStatement();
            ResultSet resultset = statement.executeQuery("select * from spot_info");

            while (resultset.next()){
                String spotName=resultset.getString(3);
                System.out.println(spotName);
            }
            if(resultset!=null){
                resultset.close();
            }
            if(statement!=null){
                statement.close();
            }
            if(connection!=null){
                connection.close();
            }
        }
        catch (SQLException e1){
            e1.printStackTrace();
        }
    }
}

PreparedStament

  • 繼承了Statement接口的接口,添加了executeQuery()空參數方法
  • 聲明類型PreparedStatement 對象,而不是Statement 對象,否則報錯
  • 預編譯的sql語句存儲在PreparedStatement對象中,執行效率高

    PreparedStatement statement = connection.prepareStatement
                ("select * from spot_info");
    ResultSet res = statement.executeQuery();
    

  • 使用佔位符:不用重複編寫結構類似的sql語句,不用拼接字符串,防sql注入,單引轉義\

    PreparedStatement statement = connection.prepareStatement
            ("insert into spot_info(spot_id_no,spot_name) values(?,?)");
    statement.setObject(1, 14);
    statement.setObject(2, "景點名");
    int changedLine = statement.executeUpdate();
    

sql注入

  //1)普通sql
  select * from spot_info where spot_id_no=11 and spot_name='南大仙林';
  //2)惡意sql,補全前一個',後一個'通過--進行轉義,中間添加or 1=1
  select * from spot_info where spot_id_no=11 and spot_name='' or 1=1 --';

Comparable和Comparator

  • Comparable:內在順序,類實現Comparable接口,this>參數,正
    • Collections.sort(list)
  • Comparator:外在順序,類沒實現Comparable接口,左>右,正
    • HelpComp類泛型實現Comparator接口,Collections.sort(List, comparator),

class Student{
    public int sex;
    public int bihuaLen;
    public Student(int sex,int bihuaLen){
        this.sex=sex;
        this.bihuaLen=bihuaLen;
    }
    public String toString(){
        return sex+" "+bihuaLen;
    }
}
class HelpComp implements Comparator<Student>{
    @Override
    public int compare(Student o1, Student o2){
        if(o1.sex<o2.sex){
            return -1;
        }
        else if(o1.sex==o2.sex){
            if(o1.bihuaLen<o2.bihuaLen){
                return -1;
            }
            else if(o1.bihuaLen==o2.bihuaLen){
                return 0;
            }
            else{
                return 1;
            }
        }
        else{
            return 1;
        }
    }
}
public class TestTreeMap{
    public static void main(String[] args){
        HelpComp help=new HelpComp();
        TreeMap tMap=new TreeMap(help);
        Student s1=new Student(0,6);
        Student s2=new Student(1,4);
        Student s3=new Student(1,3);
        Student s4=new Student(0,7);
        tMap.put(s1, 1);
        tMap.put(s2, 1);
        tMap.put(s3, 1);
        tMap.put(s4, 1);
        System.out.println(tMap);
        System.out.println(tMap.keySet());
    }
}

動態綁定

  • 聲明類型:變量被聲明時的類型
  • 實際類型:變量所引用的對象的真實類型

  • 分派:根據對象的類型對方法進行選擇,靜態多分派、動態單分派

    • 靜態分派:重載,編譯期,聲明類型,方法名參數
    • 動態分派:重寫,運行期,實際類型,方法接收者,動態置換某方法

  • 動態綁定:虛擬機預先爲每個類創建了一個方法表:方法的簽名和實例調用的方法
  • 動態綁定無需修改現存代碼,就可以對程序進行拓展,添加一個新類Executive,e可能引用該類的對象,不用對調用e.getSalary()的代碼重新編譯,自動調用Executive.getSalary()

  • obj.func(paran)隱式參數obj,實際類型爲SON
  • 可能存在多個名字爲func,但參數類型不同的方法,如func(int),func(string),編譯器列舉SON類(超類中public)名爲func的方法,匹配的過程,允許類型轉換(匹配到0或多個都報錯)

  • final 修飾方法:編譯時考慮性能,可將final函數視爲內聯函數。

//重載:WhiteCat、BlackCat繼承Cat
public class Mozi{
    public void feed(Cat cat){
        System.out.println("貓");
    }
    public void feed(WhiteCat cat){
        System.out.println("白貓");
    }
    public void feed(BlackCat cat){
        System.out.println("黑貓");
    }
    public static void main(String[] args){
        Cat wCat = new WhiteCat();
        Cat bCat = new BlackCat();
        Mozi obj= new Mozi();
        obj.feed(wCat);
        p.feed(bCat);
    }
}
//重寫:繼承覆蓋方法時,返回類型與父類相容
class Cat {
    public void eat(){
        System.out.println("吃魚");
    }
}
class WhiteCat extends Cat {
    @Override
    public void eat(){
        System.out.println("吃白魚");
    }
}
public class Mozi{
    public static void main(String[] args){
        Cat wCat = new WhiteCat();
        wCat.eat();
    }
}

繼承和複合場景

  • 對普具體類進行跨域包邊界的繼承不合適
    • 計算HashSet類中曾添加過的元素數量,addAll()通過調用add()實現
    • 1)不重寫addAll()方法,直接使用HashSet中的addAll(),通過add實現
    • 2)自己重新寫addAll()方法,耗時且容易出錯
  • 複合:不擴展現有類,在新類中,增加一個私有域,引用一個實例

單例:私有構造函數:私有靜態實例:公有靜態方法

1)餓漢:不管用不用,都先初始化好,有點浪費
class Single1{
    private Single1() {}
    private static Single1 single=new Single1();
    public static Single1 getInstance(){
        return single;
    }
}

2)懶漢粗鎖:即使是無競爭的、也被鎖降低了效率
class Single2{
    private Single2() {}
    private static Single2 single;
    public static synchronized Single2 getInstance(){
        if(single==null){
            single=new Single2();
        }
        return single;
    }
}

3)懶漢細鎖:雙重檢查法、可能因指令重排序訪問到未初始化的實例
class Single3{
    private Single3() {}
    private static Single3 single;
    public static Single3 getInstance(){
        if(single==null){
            synchronized(Single3.class){
                if(single==null){
                    single=new Single3();
                }
            }
        }
        return single;
    }
}

4)volatile修飾實例: 分配內存、初始化、指向內存
private static  volatile Single4 single;

異常分類

  • 非檢查異常:RuntimeException類及其子類
    • NullPointerException、IndexOutOfBoundsException
  • 檢查異常:Exception類中除了非檢查異常的子類
    • IOException、SQLException
  • 錯誤
    • OutOfMemoryError

  • 異常的對象從哪裏來

    • java運行時環境自動拋出的系統生成的異常
    • 程序員自己拋出的異常,throw關鍵字,常用來向調用者彙報異常的一些信息
  • 異常轉譯

    • 將一種異常轉換成另一種異常
    • 異常轉譯針對所有繼承 Throwable超類的異常類而言的
    • 在異常的層層轉譯過程中,就形成一個異常鏈,整個異常鏈保存了每一層的異常原因
  • try catch

    • try塊後面必須跟着一個catch塊或finally塊
    • try塊可有多個catch塊,每個只能定義一種異常類
    • Exception e可以捕獲所有類型的異常
    • 如果有多個catch塊,Exception e最好放在最後
    • 如果在try塊中使用了System.exit(0),finally塊不會被執行
  • System.exit(status):用來結束當前正在運行中的java虛擬機,不管status爲何值都會退出程序, 0是正常退出程序


//try/catch有return,finally塊仍會會執行   
//finall有return,會覆蓋try/catch的return語句,調用方無法收到catch異常,Eclipse會給出警告,
@SuppressWarnings("finally")
public static String test(String path){
    String ans="返回狀態";
    File file=new File(path);
    FileReader reader=null;
    try{
        reader=new FileReader(file);
        System.out.println("try");
        ans="try";
        return ans;
    }
    catch (FileNotFoundException e){
        System.out.println("catch");
        ans="catch";
        return ans;
    }
    finally{
        System.out.println("finally");
        close(reader);
        ans="finally";
        return ans;
    }
}
public static void main(String[] args){
    String ans=test("Test");
    System.out.println("test()返回:"+ans);
}

枚舉

  • static final的不足:類型不安全(int-123-4),沒有命名空間,修改要重編譯
  • 枚舉類型定義轉變成類定義

public enum StudyEnum {
    ZhangSan("長江邊上"),
    LiSi("鵝住在南極啊"),
    WangWu("黃土小坡坡啊");
    private String address;
    private StudyEnum(String address){
        this.address = address;
    }
    public String getAddress(){
        return this.address;
    }
    public static void main(String[] args){
        String address=StudyEnum.ZhangSan.getAddress();
        System.out.println(address);
        EnumSet<StudyEnum> list = EnumSet.range(StudyEnum.ZhangSan, StudyEnum.LiSi);
        for(StudyEnum ele:list){
            System.out.println(ele.getAddress());
        }

        EnumMap<StudyEnum,Integer> map=new EnumMap<StudyEnum,Integer> (StudyEnum.class);
        map.put(StudyEnum.LiSi, 4);
        Set<StudyEnum> set=map.keySet();
        for(StudyEnum ele:set){
            System.out.println(ele);
            System.out.println(map.get(ele));
        }
    }
}

優雅關閉IO流:Closeable接口

public class StduyTry{
    public static void close(Closeable obj) {
        if (obj == null){
            return; 
        }
        try {
            obj.close();
        } 
        catch (IOException e) {
        }
    }
}

equals()

  • ==:判斷兩個對象的地址是否相等、即:判斷兩個對象是不是同一個對象
  • equals:判斷兩個對象是否相等
    • 沒有覆蓋Object.equals(),默認實現是比較==
    • 覆蓋了Object.equals(),執行覆蓋後的函數進行內容相等的判斷咯

重寫equals()必須重寫hashCode()

  • 否則兩個相等的對象可能有不同的散列碼,會散列島不同的位置
  • 散列表會存在重複元素

instanceof

  • 對象instanceof類:左邊具體
  • 類.isInstance(對象)
  • 類.isAssignableFrom(類)

重寫equals()

  • 1)對稱性問題:參數.istanceof(this) 普通點(1,2) 有色點(1,2,red)

    • 普通點.equals(有色點) 左邊更具體,返回true
    • 有色點.equals(普通點) 左邊不具體,返回false
  • 2)解決對稱性:分類討論

    • 如果至少一個是普通點,直接普通點.equeals(另一個)
    • 否則,兩個都是有色點,首先super.equeals(另一個),再比較顏色

    • 3)傳遞性問題

      • 有色點.equals(普通點) 不比較顏色,返回true
      • 普通點.equals(有色點) 不比較顏色,返回true
      • 但是有色點可能顏色不符合,會違背了傳遞性
    • 4)無法在拓展可實例化的類同時、既增加新組件、又同時保留equals約定


post和get區別

  • 參數數據的存儲位置不同:get()在頭部url;post()在請求正文
  • tcp請求次數不同:get()請求一次,頭部;post()請求兩次,頭部、正文

final關鍵字

  • 修飾類:該類不可被繼承,類中所有的方法都是final、成員不影響
  • 修飾方法:可在子類中被正常繼承、但不可重寫
  • 修飾字段
    • 基本類型:只能被賦值一次
    • 非基本類型:指向哪塊內存是不可變的,但是指向的內存的內容是可以變的

String:運行時常量池

  • 1)String case1=”計算機軟件”常量池中不存在,常量池中創建,再解析引用
  • 2)String case2=”計算機軟件”常量池中已存在,直接解析引用

  • 3)String case3=”計算機”+”軟件”編譯器優化
  • 4)final String temp4=”計算機” String case4=temp4+”軟件” 編譯器優化

  • 5)String case5=new String(“計算機軟件”)
    • 如果常量池中已存在,堆中創建,返回堆中引用
    • 否則先創常量池對象,堆中創建,返回堆中引用
  • 6)String case6=case5.intern() 得到常量池中的引用

  • 7)String temp7=”計算機” String case7=temp7+”軟件”;
    • 不爲常量,不創常量池對象,堆中創建,返回堆中引用

反射:運行狀態

 every類,能知道屬性、方法;every對象,能調用屬性、方法
  • 1)類的公有方法:getMethod()
    • 自身public+基類public+接口public
  • 2)類的自身方法:getDeclaredMethod()
    • 自身public+自身protected+自身private

finalize()

  • System.gc() “強制”請求系統執行垃圾回收
    • 但是不能保證系統何時進行垃圾回收,jvm不一定會立刻執行,
    • jvm感覺內存空間有限時,纔會開始執行finalize()
  • Object.finalize() 允許被重寫
    • 是jvm自動調用的
    • 當該對象在gc roots不可達,第一次標記後,指定對象應該做什麼行爲
    • 典型的做法是釋放系統資源
  • 何時調用finalize()
    • 顯示調用
    • 對象被gc時自動調用,比如運行System.gc()的時候
    • 程序退出時爲每個對象調用一次finalize方法

Class:對象equals

  • Class屬性:編譯時決定、僅裝入內存,不鏈接、不初始化
  • Class.forName():編譯時決定、僅鏈接(靜態代碼塊)、不初始化
  • obj.getClass():運行時決定、如果沒加載鏈接、就加載鏈接、初始化

public class Test{
    {
        System.out.println("normal");
    }
    public Test(){
        System.out.println("constructor");
    }
    static{
        System.out.println("static");
    }
    public static void main(String[] args){}
}

class T{
    {
        Print.print("normal");
    }
    public static T t1=new T();
    public static T t2=new T();
    static {
        Print.print("static");
    }
}

public class LoadSeq{
    private static LoadSeq load = new LoadSeq(); 
    private static int count1;               
    private static int count2 = 2;            

    public LoadSeq(){                           
        count1++;  
        count2++;  
       Print.print("構造函數中"+count1+" "+count2); 
    }
    public static LoadSeq getLoad(){        
        return load;  
    }  
    public static void main(String[] args){
        LoadSeq.getLoad();  
        Print.print("count1="+count1);
        Print.print("count2="+count2);
        T t=new T();
    }  
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章