Java高級特征


1.static關鍵字

1)static用法總結
對於靜態方法引用其他的靜態方法和變量,在同個類中,直接調用,在不同類中,是用來類名加方法名或者類名加變量名,引用其他的非靜態變量和方法,不管是否同一個類,都需要調用對象來使用。
對於非靜態的方法引用其他的靜態和不靜態的變量和方法,在同一個類中,直接用,在不同類中,靜態方法和成員需要應用類名,而非靜態方法和變量則需要調用對象來用。


2)對於static方法和static變量的注意事項
static方法注意事項:
①.在靜態方法中不能訪問非靜態成員方法和非靜態成員變量,只能通過調用對象來用,但是在非靜態成員方法中是可以訪問靜態成員方法/變量的。
②.即使沒有顯示地聲明為static,類的構造器實際上也是靜態方法。
③. static方法一般稱作靜態方法,由於靜態方法不依賴於任何對象就可以進行訪問,因此對於靜態方法來說,是沒有this的,因為它不依附於任何對象,既然都沒有對象,就談不上this了。
static變量注意事項:
①.static變量只能是成員變量。
②.static變量也稱作靜態變量,靜態變量和非靜態變量的區別是:靜態變量被所有的對象所共享,在內存中只有一個副本,它當且僅當在類初次加載時會被初始化。
而非靜態變量是對象所擁有的,在創建對象的時候被初始化,存在多個副本,各個對象擁有的副本互不影響。
③.static成員變量的初始化順序按照定義的順序進行初始化(多個static的成員變量的時候)。


常量(final):就是定義了一個量,其是不會變化的了,不管你在后面有沒有改它,都不會變了。

 

3)static代碼塊
a.形式:eg: static{
startDate = Date.valueOf("1946");
endDate = Date.valueOf("1964");
}

b.用法說明:

①可以放在一個類中的任何地方;

②初次被加載,就是說如果再創建的話static代碼塊就不執行了,因為已經被收回了,只會執行一次;
③多個static塊,按照static塊的順序去執行;

c.為什么說static塊可以用來優化程序性能:因為只會在類加載的時候執行一次

d.何時使用:只需要進行一次的初始化操作基本都放在static代碼塊中進行


4)static關鍵字的誤區
① static關鍵字不會改變類中成員的訪問權限,其只是改變了在靜態方法中不可以直接使用非靜態方法和變量
②雖然對於靜態方法來說沒有this,但在非靜態方法中能夠通過this訪問靜態成員變量
③static是不允許用來修飾局部變量。


5)常見的筆試面試題

public class Test extends Base{

static{
System.out.println("test static");
}

public Test(){
System.out.println("test constructor");
}

public static void main(String[] args) {
new Test();
}
}

class Base{

static{
System.out.println("base static");
}

public Base(){
System.out.println("base constructor");
}
}
結果:
base static
test static
base constructor
test constructor
結果說明:先來想一下這段代碼具體的執行過程,在執行開始,先要尋找到main方法,因為main方法是程序的入口,但是在執行main方法之前,必須先加載Test類,而在加載Test類的時候發現Test類繼承自Base類,
因此會轉去先加載Base類,在加載Base類的時候,發現有static塊,便執行了static塊。在Base類加載完成之后,便繼續加載Test類,然后發現Test類中也有static塊,便執行static塊。在加載完所需的類之后,
便開始執行main方法。在main方法中執行new Test()的時候會先調用父類的構造器,然后再調用自身的構造器。因此,便出現了上面的輸出結果。
(從main方法那個類開始加載,如果有該類有父類,先加載父類,之后執行main方法(注意:如果再main方法中又出來一個類沒有加載還是要加載),如果有父類還是先父類開始)

 

.public class Test {
Person person = new Person("Test");
static{
System.out.println("test static");
}

public Test() {
System.out.println("test constructor");
}

public static void main(String[] args) {
new MyClass();
}
}

class Person{
static{
System.out.println("person static");
}
public Person(String str) {
System.out.println("person "+str);
}
}


class MyClass extends Test {
Person person = new Person("MyClass");
static{
System.out.println("myclass static");
}

public MyClass() {
System.out.println("myclass constructor");
}
}

結果:test static
myclass static
person static
person Test
test construstor
person MyClass
myclass constructor

結果說明:
首先加載Test類(其里面有main方法),因此會執行Test類中的static塊。接着main方法執行new MyClass(),而MyClass類還沒有被加載,因此需要加載MyClass類。
在加載MyClass類的時候,發現MyClass類繼承自Test類,但是由於Test類已經被加載了,所以只需要加載MyClass類,那么就會執行MyClass類的中的static塊。
在加載完之后,就通過構造器來生成對象。而在生成對象的時候,必須先初始化父類的成員變量,因此會執行Test中的Person person = new Person(),
而Person類還沒有被加載過,因此會先加載Person類並執行Person類中的static塊,接着執行父類的構造器,完成了父類的初始化,然后就來初始化自身了,
因此會接着執行MyClass中的Person person = new Person(),最后執行MyClass的構造器。
(先加載有main方法的類(有父類先加載父類),之后執行main方法(有類繼續加載)(有父類的話先執行父類的方法),加載完后就通過構造器來生成對象(也還是從有main方法的
類開始執行但(如果有父類的話,先執行父類的構造器)),如果再生成的對象中有新的類出現,繼續加載,且執行完這個類的構造方法(有父類的繼續加載),之后按照順序執行完代碼。)

 

③.

public class Test {

static{
System.out.println("test static 1");
}
public static void main(String[] args) {

}

static{
System.out.println("test static 2");
}
}

結果:

test static 1
test static 2

結果說明:雖然在main方法中沒有任何語句,但是還是會輸出,原因上面已經講述過了。另外,static塊可以出現類中的任何地方(只要不是方法內部,記住,任何方法內部都不行),
並且執行是按照static塊的順序執行的

 

2.final關鍵字

1)可以修飾類,函數,變量;
2)被fianl修飾的類不可以被繼承(如果使用這個關鍵詞修飾類是為了避免被繼承被子類復寫功能);
3)被final修飾的方法不可以被復寫;
4)被final修飾的變量是一個常量,只能賦值一次,既可以修飾成員變量,又可以修飾局部變量(當在描述事物時,一些數據的出現值是固定的,那么這時為了增強閱讀性,都給這些值起個名字,方便於閱讀,而這個值不需要改變,所以
加上final修飾,作為常量,常量的書寫規范所有字母都大寫,如果由多個單詞組成,單詞間通過_連接);
5)內部類定義在類中的局部位置上時,只能訪問該局部被final修飾的局部變量。

 

3.抽象類

1)抽象類的特點:
①抽象方法一定在抽象類中(但抽象類中不一定有抽象方法)
②抽象方法和抽象類都必須被abstract關鍵字修飾(但不代表方法都為抽象類,可為其他)
③抽象類不可以用new創建對象,因為調用抽象方法沒意義
④抽象類中的抽象方法要被使用,必須由子類復寫其所有的抽象方法后建立子類對象調用,如果子類只覆蓋了部分抽象方法,那么該子類還是抽象類。
⑤抽象類中可以定義抽象方法,但是一般類不行

 

2)例子
abstract class student{
abstract void study();//這里的方法體不用寫
abstract void study1();

class basestudent extends student{
void study(){}
void study1(){}//如果這個沒復寫該類也還是抽象類

 

4.接口

1)接口與抽象類
①接口中的所有方法都是抽象的,而抽象類可以定義帶有方法體的不同方法;
②一個類可以實現多個接口,但只能繼承一個抽象父類;
③接口與實現它的類不構成類的繼承體系,即接口不是類體系的一部分,因此,不相關的類也可以實現相同的接口,而抽象類是屬於一個類的繼承體系,並且一般位於類體系的頂層。


2)接口的定義
①理解:使用interface來定義一個接口。接口定義同類的定義類似,也是分為接口的聲明和接口體,其中接口體由常量定義和方法定義兩部分組成。
②例子:
public interface CalInterface
{
final float PI=3.14159f;//定義用於表示圓周率的常量PI
float getArea(float r);//定義一個用於計算面積的方法getArea()
float getCircumference(float r);//定義一個用於計算周長的方法getCircumference()
}
注意:為什么只能定義常量值?
因為接口中的方法都是抽象方法,只有方法的聲明,而沒有方法體。如果在一個類中定義了一個變量的話,就沒有辦法對該變量進行賦值操作,而變量就沒有了其存在的價值。


3)實現接口
①.基本格式如下:
[修飾符] class <類名> [extends 父類名] [implements 接口列表]{
................
}
注意:當接口列表中存在多個接口名時,各個接口名之間使用逗號分隔。

②例子
public class Cire implements CalInterface
{
public float getArea(float r)
{
float area=PI*r*r;//計算圓面積並賦值給變量area
return area;//返回計算后的圓面積
}
public float getCircumference(float r)
{
float circumference=2*PI*r; //計算圓周長並賦值給變量circumference
return circumference; //返回計算后的圓周長
}
public static void main(String[] args)
{
Cire c = new Cire();
float f = c.getArea(2.0f);
System.out.println(Float.toString(f));
}
}
注意:
a.在類中實現接口時,方法的名字、返回值類型、參數的個數及類型必須與接口中的完全一致,並且必須實現接口中的所有方法。
b.因為可以進行多個接口實現, 這時就可能出現(多個接口中的)常量或方法名沖突的情況,解決該問題時,如果常量沖突,則需要明確指定常量的接口,這可以通過“接口名.常量”實現。
如果出現方法沖突時,則只要實現一個方法就可以了。


4)多重繼承
理解:就是通過接口來完成多重繼承。格式為先繼承再實現,接口可多個,用","隔開。

通過繼承擴展接口
舉例說明
interface Shape{
void draw();}}
//需要加多一個功能
interface A extends Shape{
void b();}
//完成了擴展

 

5.包

1)包的概念:包(package)是Java提供的一種區別類的名字空間的機制,是類的組織方式,是一組相關類和接口的集合,它提供了訪問權限和命名的管理機制。


2).Java中提供的包主要有以下3種用途:

① 將功能相近的類放在同一個包中,可以方便查找與使用。

② 由於在不同包中可以存在同名類,所以使用包在一定程度上可以避免命名沖突。

③ 在Java中,某次訪問權限是以包為單位的。


3)創建包

a:創建包package語句的語法格式如下:

package 包名;

b說明: 1.其用於指定包的名稱,包的名稱要為合法的 Java標識符。
2.當包中還有包時,可以使用“包1.包2.…….包n”進行指定,其中,包1為最外層的包,而包n則為最內層的包。
3.package 語句通常位於類或接口源文件的第一行。


c.例如,定義一個類Circ,將其放入com.wgh包中的代碼如下:

package com.wgh;

public class Circ {

final float PI=3.14159f; //定義一個用於表示圓周率的常量PI

// 定義一個繪圖的方法

public void draw(){

System.out.println("畫一個圓形!");

}

}

 

4)使用包中的類 

a.我們可以使用包中的什么類:類可以訪問其所在包中的所有類,還可以使用其他包中的所有public類。


b.下面為使用其他包中的public類的方法:

①使用長名引用包中的類 :在每個類名前面加上完整的包名即可。

例如,創建Circ類(保存在com.wgh包中)的對象並實例化該對象的代碼如下:

com.wgh.Circ circ=new com.wgh.Circ();

 

② 使用import語句引入包中的類

import語句的基本語法格式為:import 包名1[.包名2.……].類名|*;

當存在多個包名時,各個包名之間使用“.”分隔,同時包名與類名之間也使用“.”分隔,而類名可以換成*:其表示表示包中所有的類。

例如,引入com.wgh包中的Circ類的代碼如下:

import com.wgh.Circ;

如果 com.wgh包中包含多個類,也可以使用以下語句引入該包下的全部類。

import com.wgh.*;


5)關於java的static import
a.靜態導入的作用:1.對一些工具性的,常用的靜態方法進行直接引用。
2.對常數變量進行直接引用。
(直接應用就是說不用引用類名,直接使用方法名就可以了,目的就是為了方便)

b.語法: 跟import差不多,只不過import改為 import static。

c.注意事項:

①靜態導入不可出現二義性
②過多的static import也許可能影響程序的可讀。


6)包名與包成員的存儲位置


package com.wgh;

public class Circ {

final float PI=3.14159f; //定義一個用於表示圓周率的常量PI

// 定義一個繪圖的方法

public void draw(){

System.out.println("畫一個圓形!");

}

}


上面代碼中的
Circ類的路徑為:C:\com \wgh\Circ.java.(如果保存到C盤根目錄下)
該包的路徑為:C:\com \wgh(如果保存到C盤根目錄下)

 

 

7)java源文件與類文件的管理

 

6.泛型與集合類

 

泛型

1)為什么需要泛型?

因為往集合里面加對象的時候,集合是不會記住此對象的類型的,當再次從集合中取出此對象時,該對象的類型會變成object類型(所以如果不用泛型,直接用集合,需要人為的強制轉換為具體的目標類型),而如果使用了泛型,其在編譯之后就會變成其定義的形式類型。而如果本身類型和目標類型不同,就會產生"java.lang.ClassCastException"異常。所以如果沒有定義泛型,該問題產生在運行時才會發現,而使用了泛型,因為擁有了它,我們就可以在編譯時就可以把這種問題暴露進而修改。

 

2)泛型的定義:泛型即“參數化類型”

比如 :List<String> list = new ArrayList<String>();其定義了這個集合只能加String類的對象。

3)泛型應用種類

(1)泛型類

class Utils<QQ>
{
private QQ q;
public void setObject(QQ q)
{
this.q=q;
}
public QQ getObject()
{
return q;
}
}
class GenericDemo3
{
public static void main(String[] args)
{
Util<Worker> u=new Util<Worker>();
u.setObject(new Student()):
Worker w=u.getObject();
}
}

分析:為什么需要泛型類?

①可以限定里面的對象是什么類型

②可以隨時創建另一個數據類型對象

注意:

泛型類型在邏輯上看以看成是多個不同的類型,實際上都是相同的基本類型。(簡單點說就是 傳入不同泛型實參的泛型類在內存上只有一個,但是數據還是會有變化的);

解釋說明:在編譯過程中,對於正確檢驗泛型結果后,會將泛型的相關信息擦出,也就是說,成功編譯過后的class文件中是不包含任何泛型信息的。泛型信息不會進入到運行時階段。

 

 (2)泛型方法

class Demo
{
public <T> void show(T t)
{
System.out.println("show:"+t);
}
public <Q> void print(Q q)
{
System.out.println("print:"+q);
}
}
class GenericDemo4
{
public static void main(String[] args)
{
Demo d=new Demo();
d.show("hahah");
d.show(new Integer(4));
d.print("heihei");
}
}

//正常運行。輸出hahah,4,heihei。

分析:
a:為什么要使用泛型方法呢?
因為泛型類要在實例化的時候就指明類型,如果想換一種類型,不得不重新new一次,可能不夠靈活;而泛型方法可以在調用的時候指明類型,更加靈活。

b:結論:

①泛型還可以用在方法上面且定義泛型方法時;
②在返回值前邊加一個<T>,是用來聲明這是一個泛型方法(沒有其他的意義);
③泛型方法,是在調用方法的時候指明泛型的具體類型。

 

(3)泛型類與泛型方法的結合(常見)

class Demo<T>
{
public <T> void show(T t)
{
System.out.println("show:"+t);
}
public <Q> void print(Q q)
{
System.out.println("print:"+q);
}
/* public static void method(T t)

System.out.println("method"+t);
}
特殊之處;靜態方法不可以訪問類上定義的泛型。
如果靜態方法操作的應用數據類型不確定,可以將泛型定義在方法上。下面為改動后的方法
*/
public static <T> void method(W t)
{
System.out.println("method;"+t);
}
       
}
class GenericDemo4
{
public static void main(String[] args)
{
Demo <String> d=new Demo<String>();
d.show("hahah");
//d.show(new Integer(4));加入這句編譯失敗,泛型類。
d.print("heihei");
d.print(5);//不會編譯失敗,因為其應用泛型方法
d.method("hahahha");
}
}


總結:泛型類和泛型方法很常連在一起用,且靜態方法不可以訪問類定義的泛型。

 

(4)泛型接口

interface Inter<T>
{
void show(T t);
}
class InterImpl<T> implements Inter<T>
{
public void show(T t)
{
System.out.println("show;"+t);
}
}
class GenericDemo5
{
public static void main(String[] args)
{
InterImpl<Integer> i=new InterImpl<Integer>();
i.show(4);
}
}

分析:
a.:為什么需要泛型接口::因為擁有泛型接口可以使我們使用泛型類有更好的擴展性。

b:結論:其實現泛型結構的類也要泛型。

注意:在集合中實現接口創造比較器哪里實現泛型接口的類不用泛型

 

(5)集合(其本質是用前面的類型做為基礎而形成的)

class GenerichDemo
{
public static void main(String[] args)
{
ArrayList<String> a1=new ArrayList<String>();
a1.add("abc01");
a1.add("abc0991");
a1.add("abc014");
Iterator<String> it=al.iterator();
while(it.hasNext()){
String s=it.next();
System.out.println(s+";"+s.length());
}
}
}//如果往a1加其他數據類型會在編譯時報出錯誤

結論:使用時放在類名和Iterator后面。

 

4)通配符(即"?")

a.為什么需要通配符?

因為需要傳入不同的泛型類型,如果只確定一個泛型類型,這樣在代碼上的效率很低,為了提高效率於是加了通配符。從功能上可知其是任何類型的父類。

 

b.對通配符的理解:

①其雖然效果像形參,但其不是形參,而是代替了實參,包括下面所說的上限,下線也一樣;

②通常只放在方法中的參數,用於集合取出時滿足我們需要的數據。

 

c.簡單通配符的使用:

class GenericDemo6
{
public static void main(String[] args)
{
ArrayList<String> a1=new ArrayList<String>();
a1.add("abcd1");
a1.add("abcd2");
a1.add(abcd3");
ArrayList<Integer> al1=new ArrayList<Integer>();
al1.add(4);
al1.add(5);
al1.add(6);
printColl(al);
printColl(al1);
}
public static void printColl(ArrayList<?> al)
{
Iterator<?> it=al.iterator();
while(it.hasNext())
{
System.out.println(it.next());
}
}
}
}

 

d.通配符上限

①為什么需要通配符上限?

如果只是用了?這個的話,其是所有類型的父類,如果我想要特殊的對象才能夠執行的話,我就要設立一個條件,而通配符上限就是其中的一種,其代表只有是某個類的子類才可以編譯通過。
 注意: 通常只用在方法中的參數,用於防止從集合取出時的數據不滿足我們的要求。

②例子:

import java.util.*;
class GenericDemo6
{
public static void main(String[] args)
{
ArrayList<Person> al=new ArrayList<Person>();
al.add(new Person("abc1"));
a1.add(new Person("abc2"));
al.add(new Person("abc3"));
ArrayList<Student> al1=new ArrayList<Student>();
al1.add(new Student("abc--1"));
al1.add(new Student("abc--2"));
al1.add(new Student("abc--3"));
printColl(al1);
}
public static void printColl(ArrayList<? extends Person> al)
{
Iterator<? extends Person> it=al.iterator();
while(it.hasNext())
{
System.out.println(it.next().getName());
}
}
}
class Person
{
private String name;
Person(String name)
{
this.name=name;
}
public String getName()
{
return name;
}
}
class Student extends Person
{
Student(String name)
{
super(name);
}
}

 

e.通配符下限

①為什么需要通配符下限:同樣的道理,設立一個條件,要傳進去的對象要是其下限的父類或是其父類的父類等才行,表示方法是 “? super 一個類”。

注意:通常只用在方法中的參數,用於防止從集合取出時的數據不滿足我們的要求。

②例子:

import java.util.*;
class GenericDemo6
{
public static void main(String[] args)
{
ArrayList<Person> al=new ArrayList<Person>();
al.add(new Person("abc1"));
a1.add(new Person("abc2"));
al.add(new Person("abc3"));
ArrayList<Student> al1=new ArrayList<Student>();
al1.add(new Student("abc--1"));
al1.add(new Student("abc--2"));
al1.add(new Student("abc--3"));
printColl(al);
}
public static void printColl(ArrayList<? super Student> al)
{
Iterator<? extends Person> it=al.iterator();
while(it.hasNext())
{
System.out.println(it.next().getName());
}
}
}
class Person
{
private String name;
Person(String name)
{
this.name=name;
}
public String getName()
{
return name;
}
}
class Student extends Person
{
Student(String name)
{
super(name);
}
}

 

5)泛型格式書寫總結

①集合 a b<>=new a<>;
②由集合引申出來的迭代器; Iterator<? extends Person> it=al.iterator();
③方法 public <T> void show(T t)
public static <T> void show(T t)
④類 class Utils<QQ>
⑤接口 interface Inter<T>
{
void show(T t);
}
class 類名(可有泛型,也可以沒有) implements Inter<T>
{
public void show(T t)
{
System.out.println("show;"+t);
}
} (兩種)

 

 

 

集合

1)為什么會出現集合類?

面向對象語言事物的體現是以對象的形式,所以為了方便對多個對象的操作,就對對象進行存儲,集合就是存儲對象最常用的一種方式。

 

2)數組和集合類同是容器,有什么不同?

a.數組雖然也可以存儲對象,但長度是固定的,集合長度是可變的。

b.數組中可以存儲基本數據類型,但集合只能存儲對象。

 

3)集合類的特點

a.集合只用於存儲對象

b.集合長度可變

c.集合可以存儲不同類型的對象

 

4)集合框架

常用類總結:

Collection包括List,Set,Queue,list的三個實用類包括ArrayList,LinkedList,Vector。JDK提供了Set三個使用類包括HashSet,TreeSet,LinkedHashSet。

注意:為什么會出現那么多的容器?

因為每一個容器對數據的存儲的邏輯方式都是不同。這個存儲方式叫做數據結構。

5)對集合框架的簡單理解:

 

 

 

 

6)集合常用方法

添加 add():注意:返回的對象是Object
刪除 remove()
清空集合 clear()
判斷集合時候有某元素 contains(某元素)
判斷集合是否為空 isEmpty()
獲取集合的個數(長度) size()

 

7)集合中對象的取出方法(迭代器)

使用方法:a:
ArrayList al=new ArrayList();
al.add("java1");
al.add("java2");
Iterator it=al.iterator();//獲取迭代器,用於取出集合中的元素,下面為取出方法
while(it.hasNext()){
Sop(it.next());
}

b(簡化版):
ArrayList al=new ArrayList();
al.add("java1");
al.add("java2");
for(Iterator it=al.iterator();it.hasNext();){
Sop(it.next()
}

 

8)List集合

a.特點:元素是有序的,元素可以重復。因為該集合體系有索引。
b.List的特有方法(凡事可以操作角標的方法都是該體系特有的方法)
增 add(index,element)
addAll(index,Collection)

刪 remove(index)

改 set(index,element)

查 get(index);
subList(from,to)包頭不包尾
ListIterator()

c.List擁有特有的迭代器。
c1:為什么會有特有的迭代器:因為Iterator方法是有限的,只能對元素進行判斷,取出,刪除的操作,如果想對其他的操作如添加,修改等,就需要使用其子接口ListIterator
c2:怎么獲得該迭代器:
ListIterator li=al.ListIterator();
while(li.hasNext()){
Object obj=li.next();
if(obj.equals("java2"))
li.set("java6");
}

d:List集合判斷元素是否相同的依據的是equals方法,比如說contains,remove根本方法就是equals方法
但兩者有不同,contains會全部比較一遍,而remove會確定要刪除的對象去跟集合的全部元素比較。
注意:equals方法系統自動調用。

 

9)List集合的子集合

①LinkedList

a:該集合的特點:底層使用的鏈表數據結構,特點是增刪速度很快,查詢稍慢。
b:LinkedList特有的方法:
addFirst();
addLast();
getFirst();
getLast();
removeFirst();
removeLast();
注意:getFirst();
getLast();
這兩種方法是獲取對象但是不刪除對象(元素),如果集合中沒有元素會出現NosuchElementException
removeFirst();
removeLast();
這兩種方法是獲取對象且刪除對象(元素),如果集合中沒有元素會出現NosuchElementException
在JDK1.6版本之后,這四種方法被已下取代
peekFirst();
peekLast();
不刪除
pollFirst();
pollLast();
刪除

 

②Vector

a.該集合特點:底層是數組數據結構,線程同步,后被ArrayList替代了
b:枚舉:枚舉就是Vector特有的取出方法,跟迭代器很像。
c:后來被取代的原因是:因為枚舉的名稱以及方法的名稱都太長了,不方便,所以被取代了。
d:枚舉的使用方法
Vector c=new Vector();
c.add("java1");
c.add("java2");
Enumeration en=c.elements();
while(en.hasMoreElements()){
SOP(en.nextElement())}

 

③ArrayList

a:該集合的特點:底層的數據結構使用的是數據結構,特點是查詢速度很快,但是增刪稍慢,線程不同步。
b:去除ArrayList集合中的重復元素

 

10)Set的子集合

①HashSet

a:set集合特點:元素是無序的,元素不可以重復
b:HashSet的底層數據結構:哈希表(存了一堆哈希值的表)
c:HashSet是如何保證元素的唯一性的:通過元素的兩種方法,hashcode和equals方法,首先比較哈希表的值是不是相等,才會使用equals方法看返回值是不是為true(即說明hashcode值不同不使用equals方法
,這兩種方法都是系統自動調用,但是在自定義類的時候需要復寫。

 

②TreeSet

a:重要功能:可以對Set集合中的元素進行排序,且可以自己設定該規則,有兩種排序方式。
(比較器一般放在創建該集合的()里面,或者
b:底層數據結構:二叉樹
注意:二叉樹規律:b1:以加入第一個的為參照物開始,比其小的左邊,比其大的右邊,且如果往右走或者左走還有元素的話,使用上述的規律繼續比較,直到下面沒有元素為止。
b2:由左邊往上走,其數變大,由右往下走,其數變大。
b3:輸出是小的先出
c:保證元素唯一性的依據是:compareTo方法
d:排序的兩種方式:
d1:讓元素自身具備比較性,元素需要實現Comparable接口,覆蓋comparaTo方法
d2:當元素自身不具備比較性或者具備的比較性不是我們想要的,這時我們就要自己設定一個比較器,將比較器對象作為參數傳遞給TreeSet集合的構造函數。//這個方法為主

 

11)Map集合

a.該集合特點:該集合存儲鍵值對,一對一對往里存,而且要保證鍵的唯一性。
b.該集合的常用方法:
1.添加
put(K key,V value)
putAll(Map<? extends K,? extends V> m)
2.刪除
clear()
remove(Object key)
3.判斷
containsValue(Object value)
containsKey(Object key)
isEmpty()
4.獲取
get(Object key)
size()
value()
entrySet()
keySet()

c.Map集合分出的三個集合。
c1.Hashtable:底層是哈希表數據結構,不可以存入null鍵null值,該集合是線程同步。
c2.HashMap:底層是哈希表數據結構,允許使用null值和null鍵,該集合是不同步。
c3.TreeMap:底層是二叉樹數據結構,線程不同步,可以用於給map集合中的鍵進行排序。
注意:Set底層就是使用了Map集合。

d.Map集合的兩種取出方式:
d1:Set<keySet> entryset:將map集合轉化Set集合,在Set集合存儲了map的鍵值,利用迭代器,根據get方法。獲取每一個鍵對應的值。
d2:Set<Map.Entry<K,V>> entrySet:將map集合中的映射關系存入到了Set集合中,而這個關系的數據類型就是:Map.Entry,之后利用
迭代器,利用getKey()和getValue方法獲取關系中的鍵和值。

實例:map練習(TreeMap)
import java.util.*;
class StuNameComparator implements Comparator<Student>
{
public int compare(Student s1,Student s2)
{
int num=s1.getName().compareTo(s2.getName());
if(num==0)
return new Integer(s1.getAge()).compareTo(new Integer(s2.getAge()));
return num;
}
}
class Maptest2
{
public static void main(String[] args)
{
TreeMap<Student,String> tm=new TreeMap<Student,String>(new StuNamecomparator());
tm.put(new Student("alisi2",23),"nanjing");
tm.put(new Student("blist2",25),"beijing");
tm.put(new Student("lisi4",24),"wuhan");
tm.put(new Student("list5",25),"hunan");
Set<Map.Entry<Student,String>> entrySet =tm.entrySet();
Iterator<Map.Entry<Student,String>>it =entrySet.iterator();
while(it.hasNext())
{
Map.Entry<Student,String> me=it.next();
Student stu=me.getKey();
String addr=me.getValue();
System.out.println(stu+":::"+addr);
}
}
}
class Person
{
private String name;
Person(String name)
{ return name;
}
public String toString()
{
return "person;"+name;
}
}
class Student extends Person
{
Student(String name)
{
super(name);
}
}

 

 

e.Map.Entry的Entry其實也是一個接口,它是Map接口中的一個內部接口。
interface Map
{
public static interface Entry
{
public abstract Object getKey();
public abstract Object getValue();
}
}
class HashMap implements Map
{
class hash implements Map.Entry
{
public Object getKey(){}
public Object getValue(){}
}
}

 

12)集合框架工具類——Collections

a.代碼實例:

import java.util.*;
class CollectionsDemo
{

public static void main(String[] args)
{
sortDemo();
}

public static void sortDemo()
{
List<String> list=new ArrayList<String>();
list.add("abcd");
list.add("aaa");
list.add("z");
list.add("kkkkkk");
list.add("qq");
sop(list);
Collections.sort(list);//進行自然排序
// Collections.sort(list,new StrLenComparator());進行長度排序
sop(list);
String max=Collections.max(list);
sop("max="+max)//打出自然排序的最右邊的值

/* String max=Collections.max(list,new StrLenComparator());
sop("max"+max);//打出長度排序最右邊的值
*/

}

public static void sop(Object obj)
{
System.out.println(obj);
}
}
class StrLenComparator implements Comparator<String>
{
public int compare(String s1,String s2)
{
if(s1.length()>s2.length())
return 1;
if(s1.length()<s2.length())
return -1;
return s1.compareTo(s2);
}
}

b.常用Collection方法總結:
1.halfSearch
/*int index=halfSearch(list,"aaaa",new StrLenComparator());
sop("index="+index);該方法就是按照什么排序后找出aaaa在那個
角標,從而打出其號碼,如果沒有該個元素,則按照這個排序方法排序下去應該
在那個位置插入,得出這個號碼a,返回值為-a-1;*/

方法原理:
public static int halfSearch<List<String> list,String key)
{
int max,min,mid;
max=list.size()-1;
min=0;
while(min<=max)
{
mid=(max+min)>>1;
String str=list.get(mid);

int num=str.compareTo(key);
if(num>0)
max=mid+1;
else if(num<0)
min=mid+1;
else
return mid;
}
return -min-1;
}

2.fill()
使用規律;Collections.fill(list,"pp")
作用;將list中的所有元素轉化成pp
3replaceAll()
使用法則;Collections.replaceAll(list,"aaa","pp")
作用;將list集合中的aaa元素改成pp。

4reverse()
作用;反轉某集合的元素。

5reverseOrder()
部分代碼
TreeSet<String> ts=new TreeSet<String>(Collections.reverseOrder());
//該方法是強行逆轉ts中自然排練順序
TreeSet<String> ts=new TreeSet<String>(Collections.revsenew StrLenComparator());
//該方法是強行逆轉ts按某種特殊的方式排序的順序(特定方式代碼省略了)
ts.add("abcde");
ts.add("aaa");
ts.add("kkk");
ts.add("ccc");
Iterator it=ts.iterator();
while(it.hasNext())
{
System.out.println(it.next());
}
}

6 swap()
使用法則;Collections.swap(list,1,2)
作用;將list中的角標為1和2的元素調換。

7shuffle()
使用法則;Collections.shuffle();
功能;每調用一次就重新洗牌一次。

8.toArray()
功能:集合變數組
代碼展示:
import java.util.*;
class CollectionToArray
{
public static void main(String[] args)
{
ArrayList<String> al=new ArrayList<String>();
al.add("abc1");
a1.add("abc2");
al.add("abc1");
/*
1,指定類型的數組到底要定義多長呢?
當指定類型的數組長度小於了集合的size,那么該方法內部會創建一個新的數組,
長度為集合的size。
當指定類型的數組長度大於了集合的size,就不會新創建了數組,而是使用傳遞
進來的數組。所以創建一個剛剛好的數組最優。al.size();
2,為什么要將集合變數組?
為了限定對元素的操作,不需要進行增刪了。
*/
String[] arr=al.toArray(new String(al.size()));
System.out.println(Arrays.toString(arr));
}
}

 

13)Arrays;用於操作數組的工具類,里面都是靜態方法

例子: asList;將數組變成list集合

import java.util.*;
class ArraysDemo
{
public static void main(String[] args)
{
//int[] arr={2,4,5};
//System.out.println(Arrays.toString(arr));
//將arr中的元素打出來
String[] arr=("abc","cc"c"kkkk");
list li=Arrays.asList(arr);
//將arr數組轉成集合li
//為什么要轉成集合,方便與使用集合中的各種方法而不用自己寫
/*注意;將數組變成集合,不可以使用集合的增刪方法,因為數組的
長度是固定的,如果增刪了,會發生UnsupportedOperationException*/

/*int[] nums={2,4,5};
List<int[]> li=Arrays.asList(nums);
sop(li);
其會打印出num這個數組,而不是2.4,5
因為如果數組中的元素都是對象,那么變成集合時,數組中的元素直接轉成集合中的元素
如果數組中的元素都是基本數據類型,那么會將該數組作為集合中的元素存在

所以要想打印出2.4.5
必須改動
integer[] nums={2,4,5};
List li=Arrays.asList(nums);
sop(li);

*/

 

7.包裝類與自動裝箱和拆箱

①String

a.Java中String是一個特殊的包裝類數據有兩種創建形式:
String s = "abc";
String s = new String("abc");????
第一種:先在棧中創建一個對String類的對象引用變量s,然后去查找"abc"是否被保存在字符串常量池中,如果沒有則在棧中創建三個char型的值'a'、'b'、'c',
然后在堆中創建一個String對象object,它的值是剛才在棧中創建的三個char型值組成的數組{'a'、'b'、'c'},接着這個String對象object被存放進字符串常量池,
最后將s指向這個對象的地址,如果"abc"已經被保存在字符串常量池中,則在字符串常量池中找到值為"abc"的對象object,然后將s指向這個對象的地址。
特點:JVM會自動根據棧中數據的實際情況來決定是否有必要創建新對象。
???
第二種:可以分解成兩步1、String object = "abc"; 2、String s = new String(object); 第一步參考第一種創建方式,而第二步由於"abc"已經被創建並保存到字符串常量池中
因此jvm只會在堆中新創建一個String對象,它的值共享棧中已有的三個char型值。
特點:一概在堆中創建新對象,而不管其字符串值是否相等,是否有必要創建新對象。

 


b.String常用的方法
1.獲取
int length(); //獲取長度
char charAt(int index) ; //獲取指定位置的字符
int indexOf(int ch); //返回的是ch在字符串中第一次出現的位置
int indexOf(int ch,int fromIndex); //是fromIndex指定位置開始,獲取ch在字符串中出現的位置。
int indexOf(String str); //返回的是str在字符串中第一次出現的位置,沒有返回-1.
int indexOf(String str,int fromIndex); //從fromIndex指定位置開始,獲取str在字符串中出現的位置。
int lastIndexOf(int ch); //從最右邊讀起(當你知道某個字符在后邊或者可能,可以通過這個方法增加速率或者確認)

2.判斷
boolean contains(str); //字符串中是否包含str子串
boolean isEmpty(); //字符串是否是空,原理判斷長度是否為0
boolean startsWith(str); //字符串是否以str開頭
boolean endsWith(str); //字符串是否以str結尾
boolean equals(str); //判斷字符串內容是否相同。復寫了Object類中的equals方法
boolean equalsIgnoreCase(); //判斷內容是否相同,並忽略大小寫。

3.轉換
a.將字符數組轉成字符串

構造方法:
String(char[] a); //將字符數組轉成字符串
String(char[] a,offset,count); //將字符數組中的一部分轉成字符串

靜態方法:
static String copyValueOf(char[] a);
static String copyValueOf(char[] date,int offset,int count)
static String ValueOf(char[] a);


b.將字符串轉成字符數組
char[] toCharArray();


c.將基本數據類型轉成字符串
static String valueOf(int a)
static String valueOf(double a)

4.替換
String replace(oldchar,newchar);

5.切割
String[] split(regex);

6.子串,獲取字符串中的一部分
String substring(begin);
String substring(begin,end);

7.轉換成大寫或小寫
String toUpperCase();
String toLowerCase();

8.將字符串兩端的多個空格去除
string trim();

9.對兩個字符串進行自然順序的比較
int compareTo(string);
//如果相同,返回0,如果字符串小於字符串參數,負數,大於,正數。

 

 

②StringBuffer
a.理解:
1.字符串的組成原理就是通過該類實現的。
2.可以對字符串內容進行增刪
3.其是一個容器
4.很多方法和String相同,長度可變。

b.特點:
1.長度可變化的
2.可以字節操作多個數據類型,但最終會通過toString方法變成字符串

c.方法:

1.存儲:
StringBuffer append(); //將指定數據作為參數添加到已有數據結尾處
StringBuffer insert(index,數據); //可以將數據插入到index位置。

2.刪除
StringBuffer delete(start,end); //刪除緩沖區中的數據,包含start,不包含end
StringBuffer deleteCharAt(index); //刪除指定位置的字符

3.獲取
char charAt(int index);
int indexOf(String str);
int lastIndexOf(String str);
int length();
String substring(int start,int end);

4.修改
StringBuffer replace(start,end,String);
void setCharAt(int index,char ch);

5.反轉
StringBuffer reverse();

6.void getChars(int srcBegin,int srcEnd,char[] det,int detBegin)
//該方法為將該字符串從srcBeigin到srcEnd個位置放在det數組中,並且是從detbegin這個位置開始放

 

d.StringBuffer和StringBuilder
StringBuffer是線程同步,開發建議使用這個,升級三個因素 提高效率,簡化書寫,提高安全性
StringBuilder是線程不同步

 

 

③基本數據類型對象包裝類
byte Byte
short short
int Integer
long Long
boolean Boolean
float Float
double Double
char Character

a.功能:
基本數據類型對象包裝類的最常見作用:就是用於基本數據類型和字符串類型之間做轉換。
//靜態方法
double b=Double.parseDouble("12.23"); //將字符串轉換成double類型
char b=Character.parseCharacter("a"); //將字符串轉換成字節類型

//非靜態方法
Integer i=new Integer("123");
int num=i.intValue();

b.拆箱裝箱原理
class IntegetDemo1
{
public static void main(String[] args)
{
Integer x=4; //自動裝箱,將值付給x
x=x+2; //x進行自動拆箱,變成了int類型,和2進行加法運算,之后再進行裝箱賦值給x。


c.十進制轉成其他制(都用Interger且為靜態)
toBinaryString() //轉成二進制
toOctalString() //轉成八進制
toHexString() //轉成十六進制

d.將其他進制轉成十進制
parseInt(String,int);
int x=Integer.parseInt("110",10);
將其轉成十進制

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM