成員變量 局部變量
所在位置 堆中,new對象時產生 在棧中
初始值 0或者null或者false 隨機數,不初始化沒辦法使用
2、匿名對象
new Car().num = 5;
new Car().color = "red";
new Car().run();
//上面三個語句都是使用了匿名對象。但是注意了,三個是不同的對象,當執行完第一
//個語句後,這個對象就沒有引用了,所以變垃圾了。
3、構造函數和構造代碼塊
(1)如果沒定義構造函數,系統給你創建一個默認的 Person(){}
(2)如果定義了,系統就不會創建默認的了。
(3)構造函數在對象被創建的時候調用。
(4)構造代碼塊在創建對象時必然會調用,並且優先於構造函數
{
System.out.println("構造代碼塊"); //這裏就是構造代碼塊的定義
}
4、this關鍵字,那個對象調用該函數,this就是那個對象。
Person(int age){
this.age = age;
}
當本類裏的構造函數調用本類另外一個構造函數時,使用this();進行調用。
注意,this();必須是構造函數裏的第一行
Person(String name,int age)
{
this(age);
this.name = name;
}
5、static關鍵字
(1)static的成員變量和成員函數都是隨着類的加載而加載的,生命週期最長。
所謂的加載就是使用到這個類,比如 new Person();這個時候Person類就加載進內存
還有Person.show();和在命令行中輸入java hello這三種情況會加載類進內存
但是,Person p這個語句只是定義,這個時候Person類並沒有加載進內存
(2)static的變量是分配在數據段的
(3)static的成員優先於非static的成員存在
(4)靜態的方法裏不能調用非靜態的成員變量和方法
(5)非靜態的方法裏能調用靜態的和非靜態的成員變量和方法
(6)靜態方法裏不能出現this,super這樣的關鍵字,因爲靜態的本來就可以不需對象就能調用
(7)靜態的數據時屬於類的,而不屬於某一個對象的,所以類名. 就能調用
6、靜態代碼塊
//靜態代碼塊在類加載進內存的時候執行
//當我們在命令行輸入java StaticCode時,StaticCode類就加載進內存
//只有類加載的時候 靜態代碼塊才能執行,並不是說new多少個對象就執行多少次
//然後JVM纔開始調用main方法。
//輸出結果是: b a c
public class StaticCode
{
static
{
System.out.println("b");
}
public static void main(String[] args)
{
System.out.println("a");
Test test = null; //這個時候沒有加載
new Test(); //這個時候Test類加載進內存
}
}
class Test
{
static
{
System.out.println("c");
}
}
7、JAVA內存分配圖
8、內存執行過程分析:
Person p = new Person("zhangsan",18);
(1)把Person類加載進內存
(2)如果有靜態代碼塊,則執行靜態代碼塊
(3)在堆內存裏開闢一塊空間,分配內存地址
(4)成員變量默認初始化,name=null,age=0;
(5)成員變量顯示初始化,name="lisi";
(6)構造代碼塊執行
(7)構造函數執行,name="zhangsan",age=18;
(8)把內存地址賦值給棧中的變量p
9、主函數
(1)靜態的原因是 JVM直接可以通過類名調用
(2)參數(String[] args) 對應 命令行java HelloWorld haha heihei 裏的 haha heihei
10、單例模式
(1)餓漢式,開發中用這種。
class SingleDemo{
//第一步,創建一個對象
private static SingleDemo single = new SingleDemo();
//第二步,構造函數私有化
private SingleDemo(){
}
//第三步,對外暴露獲取本類對象的方法
public static SingleDemo getInstance(){
return single;
}
}
(2)懶漢式(延遲加載的設計模式),此方式存在弊端,多線程時有可能出現多個對象的存在。
class SingleDemo{
//第一步,創建一個對象
private static SingleDemo single = null;
//第二步,構造函數私有化
private SingleDemo(){
}
//第三步,對外暴露獲取本類對象的方法
public static SingleDemo getInstance(){
if(single == null)
single = new SingleDemo();
return single;
}
}
11、繼承
class Parent
{
int num = 4;
}
class Child extends Parent
{
int num = 5;
void show(){
int num = 6;
System.out.println(num);
}
}
class Demo{
public static void main(String[] args){
Child c = new Child();
//就近原則,結果是6。如果沒有局部變量,那麼結果是5。
//this.num 那結果就是5。
//super.num 那結果是4。
//this是當前的對象
//super不是父類的對象,而是父類的內存空間。
c.show();
}
}
12、重寫
(1)重寫的方法中,子類的權限必須大於等於父類的該方法的權限
(2)靜態只能覆蓋靜態,因爲優先於對象存在。
13、繼承中構造函數特點:子類的構造函數裏,第一行有一個隱式的super()調用父類的構造函數。如果父類裏沒有默認的構造函數,而子類中的構造函數也沒有顯式調用,那必然會報錯。
14、final關鍵字
final修飾的類不能被繼承
final修飾的方法不能被重寫
final修飾的變量(成員變量和局部變量)是常量,不能再賦值。
15、abstract抽象類
(1)聲明爲抽象方法,那麼該類就必須爲抽象類。
(2)抽象類不能new對象,誰繼承了抽象類,必須重寫。
(3)當然,如果一個抽象類繼承了一個抽象類,那麼該抽象類不用重寫抽象方法,但是隻要後面的不是抽象類的
繼承了該抽象類,那麼就要重寫裏面的所有抽象方法。
abstract class Person{
abstract void show();
}
16、接口interface,其就是一個特殊的抽象類
interface Inter
{
public static final int a = 5; //接口裏的變量都是public static final修飾的
public abstract void show(); //接口裏所有的抽象方法都是public修飾的
public abstract void display();
} //同樣,實現接口,就要重寫裏面的所有的抽象方法。
(1)類與類之間是繼承關係。
(2)類與接口之間是實現的關係。
interface A
{
public abstract void show();
}
interface B
{
public abstract void display();
}
class C
{
public void func(){}
}
class D extends C implements A,B //多實現,重寫裏面的所有抽象方法
{
public void show(){}
public void display(){}
}
(3)接口與接口之間是繼承關係(可以多繼承)。
interface A
{
}
interface B
{
}
interface C extends A,B //接口之間的多繼承
{
}
17、多態
成立條件:
(1)有繼承關係
(2)方法重寫
(3)父類引用指向子類對象
abstract class A
{
abstract void eat();
}
class B extends A
{
public void eat(){
System.out.println("B");
}
public void show(){
System.out.println("B show");
}
}
class C extends A
{
public void eat(){
System.out.println("C");
}
public void display(){
System.out.println("C display");
}
}
public class Test
{
public static void main(String[] args){
A a1 = new B(); //多態,向上轉型
A a2 = new C();
a1.eat(); //調用B裏的eat方法
a2.eat(); //調用C裏的eat方法
a1.show(); //不行,show是子類特有的方法,a1是A類型,所以看不到該方法
a2.display(); //不行,理由同上
//要想調用子類裏特有的方法,怎麼辦?
B b = (B)a1; //向下轉型
b.show(); //這樣就可以調用了,因爲現在b是B類的對象
}
}
18、多態的特點
(1)成員變量,看左邊,左邊有,那就執行。
class A{
int num = 5;
}
class B extends A{
int num = 6;
}
class Demo{
public static void main(String[] args){
A a = new B();
a.num; //結果是 5
}
}
(2)成員函數,還是看左邊,執行的的時候如果發現show方法重寫了,就會執行子類show的方法
class A{
void show(){
System.out.println("A run...");
}
}
class B extends A{
void show(){
System.out.println("B run...");
}
}
class Demo{
public static void main(String[] args){
A a = new B();
a.show(); //結果是 B run
}
}
(3)靜態成員,還是看左邊,因爲很對象沒有關係。
class A{
static void show(){
System.out.println("A run...");
}
}
class B extends A{
static void show(){
System.out.println("B run...");
}
}
class Demo{
public static void main(String[] args){
A a = new B();
a.show(); //結果是 A run
}
}
19、instanceof關鍵字
abstract class Animal
{
abstract void eat();
}
class Cat extends Animal
{
void eat(){
System.out.println("cat eat");
}
}
class Dog extends Animal
{
void eat(){
System.out.println("dog eat");
}
}
public class Test
{
public static void main(String[] args)
{
Animal a1 = new Cat(); //這句話可理解爲:a1實際是一隻貓,我們叫它爲動物
Animal a2 = new Dog();
Dog d = new Dog();
System.out.println(a1 instanceof Cat); //true a1是一種貓嗎?
System.out.println(a1 instanceof Animal); //true a1是一種動物嗎?
System.out.println(a1 instanceof Dog); //false
System.out.println(d instanceof Dog); //true
System.out.println(d instanceof Animal); //true d是一種動物嗎?
}
}
20、equals的用法
class Demo
{
String name;
Demo(String name){
this.name = name;
}
public boolean equals(Object obj){ //重寫Object類裏的equals方法
if(obj instanceof Demo){
Demo d = (Demo)obj; //向下轉型,獲得Demo裏的成員變量name
return this.name == d.name;
}else{
return false;
}
}
}
public class EqualsDemo
{
public static void main(String[] args){
Demo d1 = new Demo("hello");
Demo d2 = new Demo("world");
System.out.println(d1.equals(d2)); //false
}
}
21、getClass(),獲得該對象所屬的字節碼對應的類文件對象。
通過這個對象就能獲取這類的一些相關信息,比如成員變量,方法等。
22、面試題:
//結果爲false
//首先在常量區裏有個" abc "字符串,把trim運算後的結果賦值給s1,
//注意了,此時常量區裏還沒有"abc",只有" abc "
//當出現另外一個常量"abc"時,他們明顯代表的是不同的常量
public class Test
{
public static void main(String[] args){
String s1 = " abc ".trim();
System.out.println(s1 == "abc");
}
}
23、內部類
(1)內部類可直接訪問外部類的所有成員,包括私有的成員變量和成員方法
(2)外部類不能直接訪問內部類的成員,若想訪問,必須通過對象。通過對象也能訪問到內部類的私有成員。
(3)其他類訪問內部類的方法,Outer.Inner inner = new Outer().new Inner();
(4)Inner類是可以被private修飾的,因爲它出現在Outer類的成員位置
(5)假如有外部類的成員變量x=5,內部類的成員變量x=6,內部類的function方法的
局部變量x=7。那麼在function裏執行System.out.println(x)是輸出7
執行System.out.println(this.x)是輸出6
執行System.out.println(Outer.this.x)是輸出5
從此也可以得到一個結果,內部類可以直接訪問外部類的成員,其實就是省略
寫Outer.this.x
class Outer
{
int x = 5;
class Inner
{
void function(){
System.out.println(x); //對應於上面的(1)
}
}
void show(){
Inner in = new Inner(); //對應於上面的(2)
in.function();
}
}
public class Test
{
public static void main(String[] args){
Outer.Inner inner = new Outer().new Inner(); //對應於上面的(3)
inner.function();
}
}
/******************************************************************************/
靜態內部類
(1)由於內部類在外部類裏的位置是成員,所以可以用static來修飾
(2)靜態內部類只能訪問外部類裏靜態的成員
(3)其他類訪問靜態內部類的方式Outer.Inner in = new Outer.Inner();
(4)靜態內部類裏的成員可以是靜態的,也可以是非靜態的
(5)非靜態的內部類裏的成員只能是非靜態的。
class Outer
{
private static int x = 5;
static class Inner
{
void function(){
System.out.println(x);
}
}
}
public class Test
{
public static void main(String[] args){
Outer.Inner in = new Outer.Inner();
in.function();
}
}
/******************************************************************************/
內部類出現在局部變量的位置
(1)同樣可以直接訪問外部類的成員
(2)要想訪問所在方法裏的局部變量,只能加final來修飾
(3)此內部類不能被private static等關鍵字修飾,因爲是局部變量
class Outer
{
int x = 5;
void show(){
int y = 6;
class Inner
{
void function(){
System.out.println(x); //如(1)所說,沒問題
System.out.println(y); //如(2)所說,有問題,y必須是final
}
}
new Inner().function();
}
}
public class Test
{
public static void main(String[] args){
new Outer().show();
}
}
24、匿名內部類
abstract class Demo
{
abstract void show();
}
class Outer
{
int x = 5;
void function(){
new Demo(){ //可以理解爲,有一個類繼承於Demo,創建該類的對象。
void show(){ //這個子類重寫了父類的抽象方法
System.out.println(x);
}
}.show(); //執行裏面的方法
}
}
25、修飾符的訪問權限
------------------------------------------------------------
類內部 package內 子類 其他
public 允許 允許 允許 允許
protected 允許 允許 允許 不允許
default 允許 允許 不允許 不允許
private 允許 不允許 不允許 不允許
-------------------------------------------------------------
26、異常
try{
}catch(Exception e){
//異常時執行
}finally{
//一定會執行
}
throws關鍵字:如果一個函數使用該關鍵字,那表明往外拋異常,當調用該函數的
時候,必須捕獲處理。當然你也如果不想處理可以繼續往外拋
throw關鍵字:自定義異常,相當於用這個關鍵字能產生一個異常
class MyException extends Exception
{
}
class Demo
{
int show(int a) throws MyException{ //然後往外拋纔算是完成一個自定義的異常
if(a == 0){
throw new MyException(); //自定義產生一個異常
}else{
return a;
}
}
}
//注意:RunTimeException可以不用try catch,也可以不用throws
27、包
package pack;
public class PackageDemo
{
public static void main(String[] args){
System.out.println("hello world");
}
}
dos命令窗口:
E:\java_project> javac -d . PackageDemo.java ==>當前目錄即(E:\java_project目錄)
下生成了一個整體,這個整體是文件夾名字爲pack,裏面有一個PackageDemo.class文件
E:\java_project> java pack.PackageDemo ==>執行,要寫全稱
//注意,如果不想在當前目錄下生成class文件,那麼可以在-d後指定自己設定的路徑
//但是執行的時候就要主要classpath的問題了
28、import關鍵字
爲了簡化b.packageB test = new b.packageB();寫法
import b.packageB;
packageB test = new packageB();
29、打包JAR文件
jar包:打包命令 jar -cvf haha.jar a b //把a b目錄下的class文件打包爲haha.jar
jar包的使用,直接將jar包的路徑設到classpath裏
比如在C盤的根目錄下有一個haha.jar包
set classpath=c:\haha.jar 就可以了