JAVA面向物件(初級)
Java的面向物件的特徵
1、封裝(隱藏)
對類中成員屬性進行隱藏(私有化),對類中的成員方法公共。
2、繼承
一個類A可以繼承另一個類B,這裡類A就是類B的子類,類A可以繼承類B的屬性和方法,也可以定義自己的
屬性和方法
3、多型
為了適應需求的多種變化,類可以呈現多種形態,使程式碼更加通用
1、封裝
為了提高類的隱蔽性,對類實現的細節隱藏,提供外部訪問的介面即可,提高程式碼的可擴充套件性
生活中的封裝:例如筆記本的內部結構同一封裝了,一般人使用筆記本時不需要了解筆記本的結構,而是
直接開機關機使用
對程式碼的封裝包括兩層意思:
1、對類的成員屬性的封裝 :
將屬性私有化(private),提供對屬性的訪問給屬性新增公用的getter和setter方法
2、對程式碼的封裝:
為了提高程式碼的複用性,儘量使用方法加引數傳遞對程式碼進行封裝,並使該方法公有(public)
public class People {
private String pname;
private int age;
private String sex;
// 提供 getter 和 setter
public String getPname(){
return pname;
}
public void setPname(String pname){
this.pname=pname;
}
public int getAge(){ return age; } public void setAge(int age){ // 對成員屬性的隱蔽性 可以防止隨意對屬性更改 if(age>100 || age<0){ System.out.println("賦值的年齡不合法"); return; } this.age = age; } public String getSex(){ return sex; } public void setSex(String sex){ this.sex= sex; } // 通常為了方便給屬性賦值,會提供有參構造 public People(String pname ,int age,String sex){ this.pname = pname; this.age = age; this.sex = sex; } public People(){ }
}
對於boolean型別的屬性,需要使用isXxx返回屬性的值。
封裝的有點:
1、良好的封裝可以減少程式碼的耦合性
2、對類中封裝的程式碼可以自由修改,而不會影響其他類
3、最大程度提高類中屬性的隱蔽性 和對屬性的控制
2、訪問修飾符的許可權
用於修飾類,屬性,方法的關鍵字都稱為訪問修飾符
2.1、public 公共的
可被同一個專案的所有類訪問(專案可見性)
2.2protect:受保護的
可以被自身的類訪問
可以被同包下的其他類訪問
對於不同包的,存在父子關係的子類可以訪問
2.3default 預設的
可以被自身訪問
可以被同包下的其他類訪問
2.4private:私有的
自能被自身類訪問
訪問修飾符 | 同一個類 | 同一包不同類(子類或非子類) | 不同包的子類 | 不同包 |
---|---|---|---|---|
public | √ | √ | √ | √ |
protected | √ | √ | √ | × |
預設 | √ | √ | × | × |
private | √ | × | × | × |
3、static關鍵字
static表示“靜態”,它可以修飾 屬性,方法,程式碼塊,在一個類中除了可以定義屬性、成員方法和構造器以外,還可以定義靜態的部分(靜態屬性,靜態方法,靜態程式碼塊)
static修飾屬性:稱為靜態屬性或者類的屬性
static修飾方法:稱為靜態方法或者類方法
static修飾語句塊:稱為靜態程式碼塊
static修飾的元件不需要通過物件訪問,而是直接通過類名訪問,在類一載入時會給static修飾的屬性和方法分配記憶體區,這個記憶體分佈在靜態記憶體區中。後續所有物件操作的時同一個記憶體區
案例一:
`public class Student {
// 成員屬性
String name;
// 靜態屬性 通常static寫在public的後面
static int age=20;
// 靜態程式碼塊
static{
System.out.println("這是靜態程式碼塊,在類一載入時,就會被執行,且只執行一次");
}
//成員方法 : 既可以訪問 成員屬性,也可以訪問靜態屬性
public void getInfo(){
System.out.println("姓名:"+name +" 年齡:" +age);
}
// 靜態方法 : 只能訪問靜態屬性,不能訪問成員屬性(非靜態屬性
// 這是為什麼? 由於成員屬性的存在需要依賴物件 ,
// 靜態屬性和靜態方法在建立物件之前就必須初始化並分配記憶體
public static void getStaticInfo(){
// System.out.println("姓名:"+name); 成員屬性不能被訪問
System.out.println("靜態屬性:"+age);
}
public Student(){
System.out.println("無參構造器");
}
// 構造程式碼塊
{
System.out.println("構造程式碼塊");
}
public static void main(String[] args) {
System.out.println("訪問靜態屬性:"+Student.age);
// 訪問靜態方法
Student.getStaticInfo();
// 類的元件執行順序
// 類編譯成.class檔案被JVM的類載入器載入-》
// 從上往下初始化static修飾的元件
// (靜態屬性,靜態程式碼塊,靜態方法,其中靜態方法呼叫才執行,靜態屬性和靜態程式碼塊直接分配記憶體)-》
// --》構造程式碼塊-》執行構造器 -》初始化成員屬性,成員方法
Student stu1 = new Student();
stu1.name="張三";
// 靜態屬性可以通過類名訪問,也可以通過物件名訪問
stu1.age=21;
System.out.println(stu1);
Student stu2 = new Student();
stu2.name="王麻子";
stu2.age=22;
System.out.println(stu2);
System.out.println(stu1.name);
System.out.println(stu1.age); // 22
System.out.println(stu2.name); //王麻子
System.out.println(stu2.age); // 22
System.out.println(Student.age);// 22
}
}`
案例二:靜態的變數 在同一個記憶體中
`public class People {
double height;
static int score;
static{
score++; // 1
}
public void setScore(){
score++; //81 86
}
public static void setScore2(){
score++;
}
public static void main(String[] args) {
People p1 = new People();
p1.score=80;//靜態屬性
p1.setScore();
People.score=85;
p1.height= 1.75;
People p2 = new People();
p2.setScore(); //86
p2.height= 1.80;
System.out.println(p1.score); // 86
System.out.println(p1.height); // 1.75
System.out.println(p2.score);//86
System.out.println(p2.height);// 1.80
}
} 案例三:構造程式碼塊和靜態程式碼塊的執行順序
public class UserInfo {
// 關於靜態的元件 從上往下執行
// 靜態屬性 需要先初始化 ,需要new一個物件
static UserInfo u = new UserInfo(); // 先執行構造程式碼塊 在執行構造器
static{
System.out.println("這是靜態程式碼塊,只執行一次");
}
public UserInfo(){
System.out.println("這是無參構造器");
}
{
System.out.println("構造程式碼塊");
}
public static void main(String[] args) {
// 結果
UserInfo u = new UserInfo();
}
}
`
結果:構造程式碼塊
這是無參構造器
這是靜態程式碼塊,只執行一次
構造程式碼塊
這是無參構造器
4、繼承
4.1概念
當類中都存在相同的屬性和行為時,可以將共有的屬性定義到一個新的類中,讓其他類附庸這個新類的屬性和行為,這種關係就是繼承關係
當滿足XXX是一個XXX的時候,也是繼承關係,例如 蘋果是一種水果,其中水果就是父類,蘋果就是子類,水果有多種,而蘋果只是水果的一種,所以蘋果繼承水果
其中被繼承的類時父類(超類,基類),繼承父類的是子類(新類,派生類)
4.2、繼承的語法
先定義父類
public class 父類{ }
在定義子類
public class 子類 extends 父類{ }
4.2.1子類繼承父類,子類擁有父類的哪些屬性和方法?
可訪問: 子類擁有父類的共有的屬性和方法, 同包下面的屬性和方法,不同包下的受保護的也可以訪問
不可訪問: 其中子類不能繼承 父類的私有的屬性和方法、不同包的預設屬性和方法 ,不能繼承父類的構造器
4.2.2 子類繼承父類,子類如何訪問父類的屬性和方法
屬性: 子類通過super 關鍵字訪問父類的屬性 ,子類通過this關鍵字訪問自己的屬性
方法:子類通過super掛件自方法父類的方法, 子類通過this關鍵字訪問自己的方法
注意: 這裡的this和super可以省略,省略後子類通過“就近原則”訪問屬性和方法(子類中存在就訪問子類的,子類中不存在,就訪問父類的。)
super.屬性
super.方法(引數)
構造器:子類通過super([引數]) 呼叫父類的構造器, 子類通過this([引數])呼叫 自己類的其他構造器,其中 super(引數[]) 必須寫在子類構造器的第一行
通過在子類構造器手動呼叫父類的有參構造器給父類的屬性賦值
`public class Employee {
String ename="王麻子";//員工姓名
double sal=5000 ; // 員工薪資
public Employee(String ename,double sal){
this.ename = ename;
this.sal = sal;
}
}
public class Manager extends Employee{
// 獎金
private double comm;
public Manager(String ename ,double sal ,double comm){
// 如何覆蓋父類的無參構造器 ,手動呼叫父類的有參構造
super(ename ,sal); // 只能寫在第一句
this.comm = comm;
}
}`
注意:子類構造器中預設呼叫父類的無參構造器
4.2.3、Java中只能是單繼承,一個類只能有一個直接父類的父類,可實現多層繼承
子類->父類->父類的父類
Pupil->Student->People
建立子類物件時,優先建立父類物件,再創子類物件, 執行順序 最上層父類的構造器 -》 父類構造器 -》子類構造器。
擴充套件問題:當一個類中存在static元素時,它們的執行順序是如何?
順序: 最上層父類的靜態塊 - 》 父類的靜態塊-》 子類的靜態塊- 》最上層 父類的構造塊和構造方法
-》父類的構造塊和構造方法- 》 子類的構造塊和構造方法
`public class People {
static{
System.out.println("People的靜態語句塊");
}
public People(){
System.out.println("People類的無參構造器");
}
{
System.out.println("People的構造語句塊");
}
}
public class Student extends People{
static{
System.out.println("Student 的靜態語句塊");
}
public Student(){
// 預設呼叫父類的構造器
System.out.println("Student的無參構造器");
}
{
System.out.println("Student的構造語句塊");
}
}
public class Pupil extends Student {
static{
System.out.println("Pupil的靜態語句塊");
}
public Pupil(){
// 呼叫它父類的無參構造器
System.out.println("Pupil類的無參構造器");
}
{
System.out.println("pupil的構造器語句塊");
}
}
public static void main(String[] args) {
//建立Pupil物件
Pupil pupil = new Pupil();
}`
結果:People的靜態語句塊
Student 的靜態語句塊
Pupil的靜態語句塊
People的構造語句塊
People類的無參構造器
Student的構造語句塊
Student的無參構造器
pupil的構造器語句塊
Pupil類的無參構造器
4、重寫
子類可以繼承父類的方法,但是父類的方法不能滿足子類的需要時,子類可以重寫父類的方法
重寫的必要條件:
1、兩個方法名必須相同,且存在不同類中(父子關係的類)
2、子類重寫的父類的方法,其方法的引數和返回值必須完全一樣,方法的具體實現可不一樣
3、訪問修飾符必須大於或等於父類的修飾符
注意:子類的物件呼叫父類方法時,如果子類重寫了父類的方法,則執行子類的方法,沒有重寫就執行父類的方法。
面試題:
說一下方法的重寫與過載的區別?
1、重寫必須存在於父子關係中的不同類,過載存在同類中
2、重寫必須滿足方法相同,且引數相同,返回值相同,過載滿足方法名相同,引數不同,與返回值無關。
3、重寫的訪問修飾符必須大於等於父類,過載沒有要求