繼承
- 繼承使用
extends關(guān)鍵字
Object
- 任何類最終都繼承自
java.lang.Object,一般稱之為基類;
同名的成員變量
- 子類可以定義與父類同名的成員變量,但不推薦這么做;
方法的重寫
- 子類的方法簽名與父類的一樣,叫做方法的覆蓋,重寫;
- 子類重寫的方法返回值類型必須 <= 父類的方法返回值類型;
- 子類重寫的方法權(quán)限 >= 父類的方法權(quán)限;
super
- 訪問父類的成員變量;
- 調(diào)用父類中定義的方法,包括構(gòu)造方法;
構(gòu)造方法的細節(jié)
- 子類的構(gòu)造方法,必須
先調(diào)用父類的構(gòu)造方法,然后再執(zhí)行后面的代碼; - 案例代碼:定義兩個類Student與Person且Student繼承自Student
public class Person {
public Person () {
System.out.println("Person()");
}
}
public class Student extends Person{
public Student () {
System.out.println("Student()");
}
}
public class Main {
public static void main(String[] args) {
// TODO Auto-generated method stub
Student student = new Student();
}
}
- 發(fā)現(xiàn)new Student(),依然會首先調(diào)用父類Person的構(gòu)造方法;
- 如果子類的構(gòu)造方法沒有顯示調(diào)用父類的構(gòu)造方法,編譯器會自動調(diào)用父類無參的構(gòu)造方法,若此時父類沒有無參的構(gòu)造方法,編譯器將報錯;
public class Person {
public Person () {
System.out.println("Person()");
}
public Person (int age) {
}
}
- new Student(),會首先調(diào)用父類Person的構(gòu)造方法
public Person (),Person現(xiàn)還有一個構(gòu)造方法public Person (int age),若此時將
public Person ()刪除,程序?qū)箦e,因為new Student(),會首先調(diào)用父類Person的構(gòu)造方法,發(fā)現(xiàn)找不到目標方法;還可以改成Student構(gòu)造方法,調(diào)用父類的構(gòu)造方法;
public class Student extends Person{
public Student () {
super(0);
System.out.println("Student()");
}
}
注解Annotation
- 兩個常見的注解:
- @override:告訴編譯器這是一個重寫后的方法;
- @SuppressWarnings("警告類別"):讓編譯器不生成警告信息;

image.png
- student變量沒有被使用,會被警告,消除警告,可選中student,點擊
command + 1,出現(xiàn)如下所示:
image.png - 最后成如下所示,消除了警告:

image.png
訪問控制
- Java中有4個級別的訪問權(quán)限,從高到低如下所示:
-
public:在任何地方都是可見的; -
protected:僅在自己的包中,自己的子類中可見; -
無修飾符(package-private):僅在自己的包中可見; -
private:僅在自己的類中可見;
-
- 使用注意點:
- 上述4個訪問權(quán)限都可以修飾類的成員,比如成員變量,方法,嵌套類等;
- 只有
public,無修飾符(package-private)可以修飾頂級類(Top-level Class) - 上述4個權(quán)限不可以修飾局部類,局部變量;
- 一個Java源文件中可以定義多個頂級類,public頂級類的名字必須和文件名一樣;

image.png
- 在Java中,可以類嵌套,即A類中可以定義一個B類,那么最外層的類A,就可被稱之為頂級類;
封裝
- 在Java中封裝:是指類的成員變量私有化,只能在本類中訪問,提供setter,getter方法讓外界進行訪問,如下所示:
package com.lyy.model;
public class Person {
private String name;
private int age;
public void setAge(int age) {
this.age = age;
}
public int getAge() {
return age;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
- 生成getter,setter方法的快捷鍵
shift + command + S,或者
編輯區(qū)右擊 -> source -> 選擇生成getter,setter方法
Static
static:常用來修飾類的成員,包括成員變量,方法,嵌套類;
-
成員變量被static修飾時,
- 稱之為類變量,靜態(tài)變量,其在程序運行過程中只占用一份固定的內(nèi)存(存儲在方法區(qū)),可達到數(shù)據(jù)共享;
- 可以通過
類名,實例對象進行訪問;
-
成員變量沒有被static修飾時,
- 稱之為實例變量,在每個實例對象內(nèi)部都有一份;
- 只能通過實例對象進行訪問;
-
方法被Static修飾時,稱之為類方法,靜態(tài)方法,通過類名進行調(diào)用;
- 可以通過
類名,實例對象進行訪問; - 內(nèi)部不可以使用this關(guān)鍵字;
- 可以直接訪問類方法,類變量;
- 不可以直接訪問實例方法,實例變量;
- 上述的規(guī)則都可以從this的本質(zhì)進行解釋;
- 可以通過
-
方法沒有被static修飾時,稱之為實例方法;
- 只能通過實例對象進行訪問,不可以通過類進行訪問;
- 內(nèi)部可以使用this;
- 可以直接訪問實例變量,實例方法;
- 可以直接訪問類變量,類方法;
雖然可以通過實例對象去訪問類變量與類方法,但一般情況下不推薦這么使用,還是使用類名去訪問類變量與類方法;
靜態(tài)導(dǎo)入
- 使用靜態(tài)導(dǎo)入后,就可以省略類名來訪問靜態(tài)成員(成員變量,方法,嵌套類)
- 案例代碼:
package com.sf;
import static com.sf.Person.*;
public class Main {
public static void main(String[] args) {
Person.age = 20;
System.out.println(Person.age);
Person.run();
//使用靜態(tài)導(dǎo)入后 可省略類名直接訪問
age = 10;
System.out.println(age);
run();
}
}
-
import static com.sf.Person.*;屬于靜態(tài)導(dǎo)入; - 靜態(tài)導(dǎo)入的經(jīng)典使用場景:
package com.sf;
import static java.lang.Math.PI;
public class Main {
public static void main(String[] args) {
System.out.println(2 * PI * 10);
}
}
- 省略類名,可
直接使用PI
成員變量的初始化
- 編譯器會自動為未初始化的成員變量設(shè)置初始值;
- 手動給實例變量進行初始化:
- 在聲明中;
- 在構(gòu)造方法中;
- 在初始化塊中;
- 在初始化塊中,編譯器會將初始化塊復(fù)制到每個構(gòu)造方法的頭部,
每創(chuàng)建一個實例對象,就會執(zhí)行一次初始化塊; - 案例代碼:
package com.sf;
public class Person {
//聲明
public int age = 10;
public String name = "yanzi";
//構(gòu)造方法
public Person () {
age = 10;
name = "yanzi";
}
//初始化塊
{
age = 100;
name = "yanzi33";
}
}
- 手動給類變量進行初始化:
- 在聲明中;
- 在靜態(tài)初始化塊中;
- 當(dāng)一個類被初始化時 執(zhí)行靜態(tài)初始化塊,
只會執(zhí)行一次; - 當(dāng)一個類第一次被主動使用時,JVM會對類進行初始化;
- 案例代碼:
package com.sf;
public class Person {
//聲明
public static int age = 10;
//靜態(tài)初始化塊
static {
age = 100;
}
}
- 可以有多個(靜態(tài))初始化塊,按照在源碼中出現(xiàn)的順序被執(zhí)行;
- 案例代碼:
package com.sf;
public class Person {
//靜態(tài)初始化塊
static {
System.out.println("Person -- static");
}
//初始化塊
{
System.out.println("Person -- init");
}
//構(gòu)造方法
public Person() {
System.out.println("Person -- 構(gòu)造");
}
}
package com.sf;
public class Student extends Person{
//靜態(tài)初始化塊
static {
System.out.println("Student -- static");
}
//初始化塊
{
System.out.println("Student -- init");
}
//構(gòu)造方法
public Student() {
System.out.println("Student -- 構(gòu)造");
}
}
package com.sf;
public class Main {
public static void main(String[] args) {
Student student = new Student();
}
}
- 執(zhí)行順序為:

image.png
- 類的初始化,實例的初始化,構(gòu)造方法的調(diào)用都是首先完成父類的,然后再執(zhí)行子類的;
單例模式
- 如果一個類設(shè)計成單例模式,那么在程序運行過程中,這個類只能創(chuàng)建一個實例對象;
- 餓漢式單例模式:
/**
* 餓漢式單例模式
*/
public class YYRocket {
//私有的靜態(tài)的 實例變量
private static YYRocket instance = new YYRocket();
//構(gòu)造方法私有化
private YYRocket() {}
//公共的靜態(tài)方法,返回唯一的實例對象
public static YYRocket getInstance() {
return instance;
}
}
- 懶漢式單例模式
public class YYRocket {
//私有的靜態(tài)的 實例變量
private static YYRocket instance = null;
//構(gòu)造方法私有化
private YYRocket() {}
//公共的靜態(tài)方法,返回唯一的實例對象
//存在線程安全問題
public static YYRocket getInstance() {
if (instance == null) {
instance = new YYRocket();
}
return instance;
}
}
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
YYRocket rocket1 = YYRocket.getInstance();
YYRocket rocket2 = YYRocket.getInstance();
YYRocket rocket3 = YYRocket.getInstance();
Log.v("YYRocket",String.valueOf(rocket1 == rocket2));
Log.v("YYRocket",String.valueOf(rocket1 == rocket3));
Log.v("YYRocket",String.valueOf(rocket2 == rocket3));
}
}
- 打印結(jié)果為true,推薦使用餓漢式單例模式,效率高;
final
- final可以修飾類,被final修飾的類,不能被繼承;
- final可以修飾方法,被final修飾的方法,不能被子類重寫;
- final可以修飾變量,被final修飾的變量,只能進行一次賦值,可視作常量;
常量
- 常量的寫法:
public class YYPerson {
public static final double HEIGHT = 172.5;
}
- static final 一起修飾常量,常量通常大寫;
- 如果將基本類型或字符串定義為常量,并且在
編譯時就能確定值,那么編譯器會使用常量值替代各處的常量名,類似于C語言的宏替換,通常稱為編譯時常量;
public class MainActivity extends AppCompatActivity {
static final int AGE = 100;
static final String name = "yanzi";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.v("MainActivity",String.valueOf(AGE));
Log.v("MainActivity",String.valueOf(100));
Log.v("MainActivity",name);
Log.v("MainActivity","yanzi");
}
}
嵌套類
- 嵌套類:定義在另一個類中的類;
public class OuterClass {
//非靜態(tài)嵌套類 (內(nèi)部類)
class InnerClass {
}
//靜態(tài)嵌套類
static class StaticInnerClass {
}
}
- InnerClassy與StaticInnerClass都可稱之為嵌套類;
- 非靜態(tài)嵌套類,可稱之為內(nèi)部類InnerClass;
- 在嵌套類外層的類,稱之為外部類OuterClass;
- 最外層的外部類,稱之為頂級類;
內(nèi)部類
- 沒有被static修飾的嵌套類,即非靜態(tài)嵌套類;
- 內(nèi)部類與實例變量,實例方法一樣,其與外部類的實例對象相關(guān)聯(lián),也就是說要想使用內(nèi)部類,首先必須外部類實例化對象,
- 內(nèi)部類不能定義除
編譯時常量以外的任何static成員; - 內(nèi)部類可以直接訪問外部類中所有成員,即使被聲明為private;
- 外部類可以直接訪問內(nèi)部類的成員,即使被聲明為private;
- 案例代碼一:
package com.example.java_test.java;
import android.util.Log;
public class Person {
private int age;
public int getAge() {
return age;
}
//非靜態(tài)嵌套類 (內(nèi)部類)
public class Hand {
private double height;
}
}
import com.example.java_test.java.Person;
import com.example.java_test.java.Person.Hand;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Person person = new Person();
//通過外部類實例 創(chuàng)建內(nèi)部類實例對象
Hand hand1 = person.new Hand();
Hand hand2 = person.new Hand();
}
}
- 內(nèi)存布局如下:

image.png
- 案例代碼一:
package com.example.java_test.java;
import android.util.Log;
public class Person {
private int age;
public int getAge() {
return age;
}
//訪問內(nèi)部類private成員
public void run(Hand hand) {
Log.v("Hand",String.valueOf(hand.height));
}
//非靜態(tài)嵌套類 (內(nèi)部類)
public class Hand {
private double height;
//編譯時常量
private static final int width = 10;
//訪問外部類private成員
public void show() {
Log.v("Hand",String.valueOf(age));
}
}
}
- 內(nèi)部類的細節(jié):
import android.util.Log;
public class OuterClass {
private int x = 1;
public class InnterClass {
private int x = 2;
public void show() {
Log.v("InnterClass",String.valueOf(x)); //2
Log.v("InnterClass",String.valueOf(this.x)); //2
Log.v("InnterClass",String.valueOf(OuterClass.this.x)); //1
}
}
}
靜態(tài)嵌套類
- 靜態(tài)嵌套類:被static修飾的嵌套類;
- 靜態(tài)嵌套類在行為上就是一個頂級類,只是定義的代碼寫在了另一個類中;
public class YYPerson {
public static class YYCar {
}
}
import com.example.java_test.java.YYPerson.YYCar;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
YYPerson person = new YYPerson();
//兩種創(chuàng)建方式等價
YYPerson.YYCar car = new YYPerson.YYCar();
YYCar car = new YYCar();
}
}
- YYPerson與YYCar兩者之間沒有必然聯(lián)系,所以說靜態(tài)嵌套類在行為上就是一個頂級類;
- 對比一般的頂級類,靜態(tài)嵌套類多了一些特殊的權(quán)限;
- 可以直接訪問外部類中成員,即使被聲明為private;
- 嵌套類的使用場景:
- 如果類A只用在類C內(nèi)部,可以考慮將類A嵌套到類C中;
- 封裝性更好;
- 程序包更加簡化;
- 增強可讀性,維護性;
- 如果類A需要經(jīng)常要訪問類C的非公共成員,可以考慮將類A嵌套到類C中;
- 另外也可以根據(jù)需要將類A隱藏起來,不對外暴露;
- 如果類A只用在類C內(nèi)部,可以考慮將類A嵌套到類C中;
- 如果需要經(jīng)常訪問非公共的實例成員,設(shè)計成內(nèi)部類,否則設(shè)計成靜態(tài)嵌套類;
- 如果必須先有C實例,才能創(chuàng)建A實例,那么可以考慮將類A嵌套到類C中;
局部類
- 局部類:定義在代碼塊中的類(可以定義在方法中,for循環(huán)中,if語句中等等);
- 局部類不能定義除編譯時常量以外的任何static成員;
- 局部類只能訪問final 或者 有效final的局部變量;
- 從Java8開始,如果局部變量沒有被第二次賦值,就可認定為有效final;
- 局部類可以直接訪問外部類中的所有成員,即使被聲明為private;
- 局部類只有定義在實例相關(guān)的代碼塊,才能直接訪問外部類中的實例成員;
import android.util.Log;
public class YYPerson {
private int width;
//靜態(tài)初始化塊 與 類相關(guān)
static {
class A {
}
}
//初始化塊 與實例相關(guān)
{
class A {
}
}
public void test() {
//有效final
int a = 10; //賦值會報錯
//final
final int b = 11;
for (int i = 0; i < 10; i++) {
class A {
}
}
if (true) {
//局部類
class A {
void test() {
Log.v("test",String.valueOf(a));
Log.v("test",String.valueOf(b));
Log.v("test",String.valueOf(width));
}
}
}
}
}
抽象方法
- 抽象方法:被abstract修飾的方法;
- 只有方法聲明,沒有方法實現(xiàn);
- 不能時private權(quán)限(因為定義抽象方法的目的是讓子類去實現(xiàn))
- 只能是實例方法,不能是類方法;
- 只能定義在抽象類,接口中;
抽象類
- 抽象類:被abstract修飾的類;
- 定義抽象類的目的是給其他類繼承的,所以不能用final修飾;
- 可以定義抽象方法;
- 不能實例化,但可以自定義構(gòu)造方法;
- 子類必須實現(xiàn)抽象父類中的所有抽象方法(除非子類也是一個抽象類);
- 可以像非抽象類一樣定義成員變量,常量,嵌套類型,初始化塊,非抽象方法等;
- 使用場景:
- 抽取子類的公共實現(xiàn)到抽象父類中,要求子類必須要單獨實現(xiàn)的定義成抽象方法;
public abstract class Shap {
protected double area;
protected double girth;
public double getArea() {
return area;
}
public double getGirth() {
return girth;
}
//抽象方法
abstract public void show();
}
package com.example.java_test.java;
import android.util.Log;
public class Rectangle extends Shap{
private double width;
private double height;
public Rectangle(double width, double height) {
this.width = width;
this.height = height;
}
@Override
public void show() {
area = width * height;
girth = (width + height) * 2;
Log.v("Circle","area:" + String.valueOf(area)+ " girth:" + String.valueOf(girth));
}
}
import android.util.Log;
public class Circle extends Shap{
private double radius;
public Circle(double radius) {
this.radius = radius;
}
@Override
public void show() {
area = Math.PI * radius * radius;
girth = Math.PI * radius * 2;
Log.v("Circle","area:" + String.valueOf(area)+ " girth:" + String.valueOf(girth));
}
}
import com.example.java_test.java.Circle;
import com.example.java_test.java.Rectangle;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Circle circle = new Circle(10);
circle.show();
Rectangle rectangle = new Rectangle(10,20);
rectangle.show();
}
}
