1. 繼承 在 中的三大特性中存在一種為繼承,繼承究竟是用來解決什麼問題的呢?在我們寫代碼的時候,我們會在一些類中使用相同的屬性和方法, 如兩個不同的人(類),共同都有年齡,身高,體重等。 那麼我們就可以把這些相同的屬性和方法提取到一個新的類中,用繼承的方法,讓一個類繼承另一個類,那麼這個類就具有它 ...
1. 繼承
在Java
中的三大特性中存在一種為繼承,繼承究竟是用來解決什麼問題的呢?在我們寫代碼的時候,我們會在一些類中使用相同的屬性和方法,如兩個不同的人(類),共同都有年齡,身高,體重等。
那麼我們就可以把這些相同的屬性和方法提取到一個新的類中,用繼承的方法,讓一個類繼承另一個類,那麼這個類就具有它的屬性和方法了。
class Student{
String name;
int age;
void study(){
System.out.println("study");
}
}
class Worker{
String name;
int age;
void work(){
System.out.println("work");
}
}
具有相同屬性:
String name;
int age;
繼承案例:
class Person{
String name;
int age;
}
class Student extends Person{
void study(){
System.out.println("study");
}
}
class Worker extends Person{
void work(){
System.out.println("work");
}
}
利用關鍵字extends
,讓類與類之間產生了關係,一個為父類,子類繼承父類,那麼子類就具有父類的屬性和方法了。Java
只支持單繼承,不允許多繼承,繼承是為了減少重覆代碼,提高代碼的復用性。
在現實世界當中,繼承就是兒子得到老子的東西,在面向對象的世界當中,繼承就是一個類得到了另一個類當中的成員變數和成員方法
在
Java
中的繼承,其實就是繼承全部屬性和方法(除了構造方法),除了private
修飾的變數或者方法,子類無法進行訪問
class Person{
String name;
int age;
Person(){
System.out.prinltn("Person的無參數構造函數");
}
Person(String name,int age){
this.name=name;
this.age=age;
System.out.println("Person有參數的構造函數");
}
void eat(){
System.out.println("定義吃飯的方法");
}
}
class Student extends Person{
//子類繼承父類
Student(){
//父類
super();
System.out.println("Student的無參數構造函數");
}
Student(String name,int age,int id){
super(name,age);
this.id=id;
}
}
在這裡一個子類只能繼承一個父類,一個父類卻可以有很多的子類,如同你只有一個親爸,但你親爸可以有多個兒子一樣。
繼承重點為了提高代碼的復用性,避免方法的調用產生歧義
2. super的使用
使用super
調用父類構造函數的方法
例子:
class Person{
String name;
int age;
Person(){
System.out.prinltn("Person的無參數構造函數");
}
Person(String name,int age){
this.name=name;
this.age=age;
System.out.println("Person有參數的構造函數");
}
void eat(){
System.out.println("定義吃飯的方法");
}
}
class Student extends Person{
//子類繼承父類
Student(){
//父類 調用父類的無參構造函數
super();
System.out.println("Student的無參數構造函數");
}
Student(String name,int age,int id){
super(name,age);
this.id=id;
}
}
super()
在子類中調用父類對象的引用,通過super()
方法調用父類中的方法和屬性,如果沒有在子類寫入super
語句,那麼在編譯的時候回自動添加一個super()
語句,super()
語句必須放在子類構造方法中的第一行,如果父類中只提供了有參的構造函數,那麼就必須手動添加對應的super
有參的語句。
super()
調用父類,父類對象的引用,代表一個虛擬對象。
3. 方法的重寫,重載
重載的表達
class A{
void funA(){
System.out.println("沒有參數的funA函數");
}
void funA(int i){
System.out.println("有參數的funA函數");
}
void funA(int i,double d){
System.out.println("擁有兩個參數的funA函數");
}
}
什麼是覆寫(意思和重寫一樣唄)
具有父子關係的兩個類中,父類和子類各有一個函數,這兩個函數的定義(返回值類型,函數名,參數列表)完全相同
重寫和重載
重載:
方法名一樣,但是參數類型不一樣(不同的參數個數,不同的參數類型,不同的參數次序)
重寫:
子類中定義的某個方法與其父類有相同的名稱和參數,則該方法被重寫了,就是一個方法重寫一遍,一模一樣的,這下記住了吧~
方法的重寫案例:
// 重寫時,註意:子類的方法許可權修飾符要大於等於父類對應的方法的許可權修飾符
// 許可權修飾符:public > protected > 預設 > private
// 如果父類的方法返回值類型是引用類型,那麼子類方法的返回值類型要麼與父類一致,要麼是父類返回值類型的子類
class A {
protected void add(){}
}
class B extends A {
protected void add(){}
}
4. 多態
多態:是為了提高功能的擴展性,提高復用,為父類的引用指向了子類的對象,多態,多種形態的體現。
多態的體現:
- 編譯時的體現:方法的重載
- 運行時的體現:向上轉型,方法的重寫
class A{
void funA(){
System.out.println("沒有參數的funA函數");
}
void funA(int i){
System.out.println("有參數的funA函數");
}
void funA(int i,double d){
System.out.println("擁有兩個參數的funA函數");
}
}
多態步驟
- 有繼承關係;
- 子類要重寫父類的方法;
- 父類要指向子類的引用
案例
// 抽象動物類
abstract class Animal {
// 抽象的方法
abstract void eat();
}
// 子類繼承父類
class Cat extends Animal {
// 重寫了父類的方法
public void eat() {
System.out.println("吃魚~");
}
// 添加了功能
public void work() {
System.out.println("抓老鼠~");
}
}
// 子類繼承了父類
class Dog extends Animal {
public void eat() {
System.out.println("吃骨頭~");
}
// 添加了自己的功能
public void work() {
System.out.println("看家~");
}
}
// 測試類
public class DemoTest {
public static void main(String[] args) {
// 父類指向子類的對象
// 向上轉型
Animal a = new Cat();
// 調用 Cat 的 eat方法
a.eat();
// 現行判斷
if(a instanceof Cat) {
// 向下轉型
Cat c = (Cat)a;
// 調用 Cat 的 work 方法
c.work();
} else if(a instanceof Dog) {
Dog d = (Dog)a;
d.work();
}
}
}
5. static靜態
被static
修飾的變數為靜態變數
被static
修飾的方法為靜態方法
靜態變數屬於類而不屬於類的某個實例,可被直接類名調用,所以叫類變數
靜態方法屬於類而不屬於類的某個實例,可被直接類名調用,所以叫類方法
非靜態的成員變數和方法,必須通過實例化後通過對象名來調用
靜態方法
class Demo {
// 定義一個函數
public void fun1() {
System.out.println("Hello");
}
// 定義一個靜態函數
public static void fun2() {
System.out.println("hello");
}
}
public class DemoTest {
public static void main(String[] args) {
// 創建對象
Demo d = new Demo();
d.fun1();
// 對靜態函數進行調用
Demo.fun2();
// 創建對象
Demo d2 = new Demo();
d2.fun2();
}
}
靜態修飾的調用方式:1)類名.方法名; 2)對象.方法名
static
用來修飾變數,方法,代碼塊,內部類。
靜態變數優先於對象出現,通過類名來調用靜態變數,同樣可以通過對象調用,靜態變數在類載入的時候載入到方法區並賦予預設值。
加入
static
使用,這個是修飾符,為靜態,被static
修飾的為靜態方法,可以直接被類名調用,當然也是可以被對象調用的。
// 定義方法
public static void sleep(){
System.out.println("睡覺");
}
}
class PersonDemo{
public static void main(String[] args){
// 類的調用
Person.sleep();
}
}
static
修飾成員變數,即為靜態成員變數;修飾方法,為靜態方法,修飾類,為靜態類。靜態方法只能訪問靜態變數,不能訪問非靜態的。
static
解決了不用創建對象的問題,將方法改為靜態,可讓功能不需要訪問類中定義的成員變數,就不用創建對象來浪費空間了。所以在Java
中靜態的添加就是為瞭解決這些問題。
在靜態方法中隨著類的載入而載入,隨著類的消失而消失;我們可知靜態方法不能訪問非靜態的,可被類名直接調用,而且在靜態方法中不能出現this,super
的關鍵字。
靜態方法註意事項:
- 在靜態方法中不能在本類中使用非靜態屬性和非靜態的方法
- 靜態方法中可以進行重載,靜態方法也可以被繼承,但不能被重寫(靜態可重載,可繼承,不能被重寫)
對於靜態代碼塊(類只載入一次)
格式:
// 父類靜態 -> 子類靜態 -> 父類非靜態 -> 子類非靜態
static {}
// 隨著類的載入執行,類只載入一次,靜態代碼塊只執行一次
- 靜態變數 (類變數)
隨著類的載入而載入,併在方法區內進行賦予預設值 - 靜態方法 (類方法)
隨著類的載入而載入,存儲在方法區中,只有被調用的時候才到棧記憶體中執行 - 靜態代碼塊 (用static{ }定義)
6. final修飾符
final
用來修飾數據,方法,類
用來修飾數據的為常量,定義好後不能改變,基本類型指定的是實際的值,引用類型指定的是地址。
public static void main(String[] args){
final int i = 3;
System.out.println(i);
}
重點:
final
修飾方法,方法不能被重寫,可重寫,可被繼承final
修飾類,不能被繼承
面向對象,面向過程:面向過程看重過程中的每一步,而面向對象看重的是對象,簡單的事務一般用面向過程,複雜的事務一般建議用面向對象,因為,先有面向過程,才有的面向對象,面向對象是程式員思想的提升,面向對象是基於面向過程的。
類和對象,類是對象的概括,對象則是類的具體表現,如
java
中的類,不是那麼的具體,而對象就是類的具體的表現了。
在棧的記憶體中存儲的是對象的地址引用,而在堆記憶體中存儲的是實際的對象,對象的賦值實質是傳遞地址值。
this
和super
必須在構造方法的第一行。
在初始化代碼塊/構造代碼塊中,優先於構造方法執行。
局部代碼塊,用於限制變數的生命周期和提高棧記憶體的利用。
結語
- 下麵我將繼續對
Java
、Android
中的其他知識 深入講解 ,有興趣可以繼續關註 - 小禮物走一走 or 點贊