數據庫連接池的理解和優化、事物處理
- 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
- 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
- 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();
}
}