知識點


基礎知識的總結
數據類型:基本數據類型和引用數據類型
基本數據數據類型(boolean.byte.short.int.lang.float.double.char)
引用類型(類、接口、數組)
重載(overLoad)和重寫(override)
重載滿足要素:方法名相同、參數的類型和參數的個數不同,和方法返回值、修飾符等無關
重寫滿足要素:方法名相同、形參列表相同、返回值類型比父類返回值更小或相等、訪問權限比父類方法更大或相等
java的標示符規則:
1.字母、數字、下劃線、美元符號,並且不能以數字開頭
2.標示符不能爲java的關鍵字和保留字符(goto)
基本類型轉換字符串的方法:
基本類型轉換成字符串的的方法:
第一種:String.valueof(基本類型)
第二種:空字符串加上基本類型,得到基本類型字符串(這裏是空字符串不是空格字符串)
第三種:調用對象的toString()
字符串轉換成基本類型的兩個方法:
1、調用基本類型封裝類的paresexxx靜態方法
2、用字符串構造基本類型,再調用封裝對象的xxxValue方法
------------------------------------
  Set set = hashMap.keySet();
                //問題1:hashMap.keySet方法返回一個Set對象,Set是接口,
                //接口可以有引用,並指向其子類對象。但是怎麼可以有一個引用set指向自己的對象呢?
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Set;


public class CollectionDemo {

        public static void main(String[] args) {

                Person p1 = new Person(21);
                Person p2 = new Person(23);
                Person p3 = new Person(21);
               
                HashMap hashMap = new HashMap();
                hashMap.put("zhangsan", p1);
                hashMap.put("lisi", p2);
                hashMap.put("wangwu", p3);
               
                Set set = hashMap.keySet();
                //問題1:hashMap.keySet方法返回一個Set對象,Set是接口,
                //接口可以有引用,並指向其子類對象。但是怎麼可以有一個引用set指向自己的對象呢?
                Iterator i = set.iterator();
                while(i.hasNext()){
                        String s = i.next();//這裏提示錯誤,應該把s的類型改爲person
                        //問題2:i.next方法應該返回一個String,這裏爲什麼會報錯?
            解答:其實在java的hashMap中還有一個內部類,這個類就是keySet
你可以在你的代碼中用 System.out.println(hashMap.keySet().getClass().getName())試試看,
返回的java.util.HashMap$KeySet,這就代表Set通過keySet方法獲得的Set對象其實是hashMap的內部類實例。而對於註釋部分的keySet,因爲keySet其實只需要有一個就可以了,因爲每個hashMap集合只可能有一種key隊列,多了就浪費空間了,所以除了第一次會new一個新的對象,你再次調用,就把以前已經創建的keyset對象給你
                        //並提示應該把s的類型改爲person?
                        System.out.println(i.next());//而這裏直接打印出的又是person。
   解釋:②因爲你沒有加泛型限定,所以i.next返回的是Object類型的,必須要進行強轉或者對迭代器進行類型限定,你這裏就限定成String類型                      
                }
        }
}

     Constructor[] constructors=Class.forName("java.lang.String").getConstructors();
---------------------------------------------------------------------------------
synchronized:在代碼裏,synchronized類似“面向對象”,修飾類、方法、對象
Lock:不作爲修飾,類似“面向過程”,在方法中需要鎖的時候lock,在結束的時候,unlock(一般在finally塊裏)
   代碼:
   public void metho(){
   synchronized(this){//舊鎖,無須人工釋放
    System.out.println(1);   
  }
  }


public void method2(){
  Lock lock=new ReentrantLock();
  lock.lock();//上鎖
  try{
  System.out.println(2);
    }finally{
  lock.unlock();//解鎖
}
synchronzied--對象加鎖:
       所有對象都自動含有單一的鎖,jvm負責跟蹤對象被加鎖的次數。如果一個對象被鎖,其記數變爲0。在任務(線程)第一次給對象加鎖的時候,記數變爲1。每當這個相同的任務(線程)在此對象上獲得鎖時,記數會遞增。只有首先獲得鎖的任務(線程)才能繼續獲取該對象上的多個鎖。每當任務離開時,記數遞減,當記數爲0的時候,鎖被完全釋放。sychronized就是基於這個原理,同時synchronized考某個獨享的單一鎖技術的次數來判斷是是否被鎖,所以無需(也不能)人工干預鎖的獲取和釋放。

}
Lock---基於棧中的框架,而不是對象級別:
       lock不同於synchronized,它基於棧中的框架而不是某個具體對象,所以Lock只需在棧裏設置鎖的開始和結束(lock和unlock)的地方,就行了(人工必須註明),不需要關心框架大小對象的變化等等。這麼做的好處是Lock能提供無條件的、可輪詢的、定時、可中斷的鎖獲取操作,相對於synchronized來說,synchronized的鎖的獲取和釋放不在一個模塊裏,獲取和釋放的順序必須相反,而Lock則可以在不同範圍內獲取釋放,並且順序無關。

------------------------------------------------------------------
TreeSet的排序方式有下面兩種:
1:讓元素自身具備比較性。元素需要實現Comparable接口,覆蓋compareTo方法。
    也種方式也成爲元素的自然順序,或者叫做默認順序。
class Student implements Comparable//該接口強制讓學生類具備比較性
{  Student()
    {}
    public int compareTo(Object obj)
    {}
}

2:當元素自身不具備比較性時,或者具備的比較性不是所需要的。這時就需要讓集合自身具備比較性。
    在集合初始化時,就有了比較方式。
    這時就需要定義一個比較器類去實現Comparator,並重寫compare方法。
class MyCompare implements Comparator  //自定義比較器,使集合具備比較性
{  public int compare(Object o1,Object o2)
    {}
}

在定義集合時,需要根據實際情況選擇排序方式:
1、TreeSet ts =new TreeSet(); //此時的排序方式爲第一種,即元素的自然排序方式。
2、TreeSet ts =new TreeSet(new MyCompare()); //此時的排序方式爲第二種,即集合自身具備比較性。
---------------------------------------------------------------------------------------------
Set:無序,不可以重複元素
  |---Hashset:數據結構式哈希表。線程是非同步的。
      包成元素唯一性的原理:判斷元素的hashCode值是否相同
      如果相同,還會繼續判斷元素的equals方法,是否爲true。
      採用hash表
  |---Treeset:可以對Set集合中的元素進行排序
       底層數據結構式二叉樹
       保證元素唯一性的依據:
       compareTo方法 return ();和hash表沒關係
       TreeSet排序的第一種方式:讓元素自身具備比較性。元素需要實現Comparable接口,覆蓋compareTo方法
       這種方式也成爲元素的自然排序,或者叫做默認排序。
     注意:排序時,當主要條件相同時,一定判斷一下次要條件。當對象很多時,耗時。
     treeset採用二叉樹形式保存數據!保存數據後查詢的時候採用折半查詢
      TreeSet排序的第二種方式:
      當元素自身不具備比較性時,或者具有的比較性不是不是所需要的。
      這時就需要讓集合自身具備比較性,定義比較器,將比較器對象作爲參數傳遞給TreeSet集合的構造函數
      在集合初始化時,就有了比較方式。
----------------------------------------------------------------------------------------------

解釋是這樣的,當你往集合中添加第一個元素的時候,(不管你重寫不重寫)集合都會自動調用hasCode方法,算出一個哈希值
當你再往集合中添加元素時。系統會再算出此元素的哈希值,並自動判斷跟之前元素的哈希值是否相同。如果相同,就需要equals方法,來判斷元素的屬性是否都一樣。
給你舉個例子

元素要往哈希表結構的容器中存儲,必須具備hashCode和equals方法。(Object已經提供了這兩個方法。  對象創建在堆內存中就是因爲有了hashCode方法.)
//覆寫hashCode方法的原因。Object中的hashCode是本地(windows)方法,只算內存地址.
//不覆寫會根據內存地址判斷資料相同的人不是同一個人。
//滿足不了人的姓名和年齡相同 既爲同一個人的要求。所以要依據對象自身特別不同。

//覆寫equals的原因:HashSet判斷元素唯一的依據是自動調用equals方法。
//不覆寫的話,如果hash值萬一相同的話,就需要逐個比較元素的屬性,而原來的equals滿足不了這個要求
代碼如下:
@Override
// 覆寫hashCode方法的原因。Object中的hashCode是本地(windows)方法,只算內存地址.
        // 不覆寫會根據內存地址判斷資料相同的人不是同一個人。
        // 滿足不了 人的姓名和年齡相同 既爲同一個人的要求。所以要依據對象自身特別不同。
        public int hashCode() {
                final int prime = 31;
                return name.hashCode() + age * prime;
                // *prime的原因。防止姓名的哈希值是40,年齡是20 與姓名的哈希值是20,年齡是40 。而引起哈希值相同,多運行equals方法
        }

        @Override
        // 覆寫equals的原因:HashSet判斷元素唯一的依據是自動調用equals方法。
        // 不覆寫的話,如果hash值萬一相同的話,就需要逐個比較元素的屬性,而原來的equals滿足不了這個要求,
//如果主方法中添加的元素內容不是一模一樣的,幾乎不可能調用equals方法。
-----------------------------------------------------------------------------------------------
/首先,內部類其實就是一個子類對象
//其實內部類的出現,在一定意義上實現了多繼承。因爲內部類 可以有多個,分別繼承別的類。外部類也可以用內部類裏的方法了。
//然後,關於你的問題。子類如果想繼承抽象內部類,就必須在這個類中定義一個帶有外部類對象的構造方法,並在構造方法中調用外部類.super();

代碼如下:
class Outer {
abstract class Inner {
  abstract void show();
  public void print() {
  }
}
}
class Test extends Outer.Inner {// 如果不這麼繼承,必須導入Inner類的包。
Test(Outer out) {
  out.super();
}
@Override
void show() {
}
}
兩外一種解釋:
class AbstractTest {  //這裏類修飾符可以使用abstract 修飾
    static abstract class A{
   /* A作爲抽象類,那麼static 必須保留,做爲類靜態成員變量。 A內部類,爲外部類AbstractTest 的一個成員屬性,隨着對象的創建而加載,不能直接調用內部類,要調用只能new AbstractTest ().A。要想繼承的話,只能把內部類改成靜態內部類,static abstract class A {},此時對着類的加載而加載。*/
        abstract void say();
        }
   
      void c(){
       System.out.println("sss");
       }

}
class B extends AbstractTest.A{
     public static void main(String[] args){

}

    @Override
    void say() {
        // TODO Auto-generated method stub
        }
}
重點:非靜態內部類,伴隨着類的實例化開闢內存單元。 A抽象內部類,爲外部類AbstractTest 的一個成員屬性,隨着對象的創建而加載,不能直接調用內部類,要調用只能new AbstractTest ().A。要想繼承的話,只能把內部類改成靜態內部類,static abstract class A {},此時對着類的加載而加載。
---------------------------------------------------------------------------------
--------- javac ----------
Main.java:11: 錯誤: 需要包含Outer.InnerAbs的封閉實例
class AA extends Outer.InnerAbs
^
1 個錯誤
爲什麼會產生這樣的錯誤?
能不能修改這個錯誤,同時還能保證AA能夠繼承Outer.InnerAbs ?
-----------------------------

編譯器的意思是:要創建Outer.InnerAbs的子類對象必須保留一個外部類的引用。

原理如下:
當創建一個子類時,子類構造函數總會調用父類的構造函數,因此在創建
非靜態內部類的子類時,必須保證讓子類構造函數可以調用非靜態內部類
的構造函數,調用非靜態內部類的構造函數時,必須存在一個外部類對象,
因爲當調用非靜態內部類的實例方法時,必須有一個非靜態內部類實例,
而非靜態內部類實例必須寄存在外部內實例裏。

代碼可以修改如下:
class Outer
{
       int a=90;
       public abstract class InnerAbs
       {
             int b=80;
             abstract void inAbs();
       }
}

class AA extends Outer.InnerAbs
{
      //顯式定義AA(非靜態內部類子類)的構造函數
      AA(Outer out)
      {
         out.super();
      }

      void inAbs()
      {
            System.out.println("AA……inAbs");
      }
}

class Main
{
      public static void main(String[] args)
      {
            Outer out = new Outer();
            //非靜態內部類子類的創建
            AA aa = new AA(out);
            aa.inAbs();
      }
}




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