代碼塊的概述和分類
-
根據其位置和聲明的不同,代碼塊可以分為局部代碼塊,構造代碼塊,靜態代碼塊,同步代碼塊。
-
常見代碼塊的應用
- a:局部代碼塊
- 在方法中出現;限定變量生命周期,及早釋放,提高內存利用率
- b:構造代碼塊 (初始化塊)
- 在類中方法外出現;多個構造方法方法中相同的代碼存放到一起,每次調用構造都執行,並且在構造方法前執行
- c:靜態代碼塊
- 在類中方法外出現,並加上static修飾;用於給類進行初始化,在加載的時候就執行,並且只執行一次。
- 一般用於加載驅動
- a:局部代碼塊
class Demo1_Code {
public static void main(String[] args) {
{
int x = 10; //限定變量的聲明周期
System.out.println(x);
}
Student s1 = new Student();
System.out.println("---------------");
Student s2 = new Student("張三",23);
}
static {
System.out.println("我是在主方法類中的靜態代碼塊");
}
}
class Student {
private String name;
private int age;
public Student(){
//study();
System.out.println("空參構造");
} //空參構造
public Student(String name,int age) {//有參構造
//study();
this.name = name;
this.age = age;
System.out.println("有參構造");
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setAge(int age) {
this.age = age;
}
public int getAge() {
return age;
}
{ //構造代碼塊:每創建一次對象就會執行一次,優先於構造函數執行
//System.out.println("構造代碼塊");
study();
}
public void study() {
System.out.println("學生學習");
}
static { //隨着類加載而加載,且只執行一次
System.out.println("我是靜態代碼塊"); //作用:用來給類進行初始化,一般用來加載驅動
} //靜態代碼塊是優先於主方法執行
}
運行結果
繼承
class Demo1_Extends {
public static void main(String[] args) {
Cat c = new Cat();
c.color = "花";
c.leg = 4;
c.eat();
c.sleep();
System.out.println(c.leg + "..." + c.color);
}
}
class Animal {
String color; //動物的顏色
int leg; //動物腿的個數
public void eat() { //吃飯的功能
System.out.println("吃飯");
}
public void sleep() { //睡覺的功能
System.out.println("睡覺");
}
}
class Cat extends Animal {
}
class Dog extends Animal {
}
/*
extends是繼承的意思
Animal是父類
Cat和Dog都是子類
*/
-
A:繼承的好處
- a:提高了代碼的復用性
- b:提高了代碼的維護性
- c:讓類與類之間產生了關系,是多態的前提
-
B:繼承的弊端
-
類的耦合性增強了。
-
開發的原則:高內聚,低耦合。
-
耦合:類與類的關系
-
內聚:就是自己完成某件事情的能力
-
-
Java中類的繼承特點
- a:Java只支持單繼承,不支持多繼承。(一個兒子只能有一個爹)
- 有些語言是支持多繼承,格式:extends 類1,類2,...
- b:Java支持多層繼承(繼承體系)
- 如果想用這個體系的所有功能用最底層的類創建對象
- 如果想看這個體系的共性功能,看最頂層的類
- a:Java只支持單繼承,不支持多繼承。(一個兒子只能有一個爹)
-
繼承的注意事項
- a:子類只能繼承父類所有非私有的成員(成員方法和成員變量)
- b:子類不能繼承父類的構造方法,但是可以通過super關鍵字去訪問父類構造方法。
- c:不要為了部分功能而去繼承
- 項目經理 姓名 工號 工資 獎金
- 程序員 姓名 工號 工資
this和super的區別和應用
- this:代表當前對象的引用,誰來調用我,我就代表誰
- super:代表當前對象父類的引用
- this和super的使用區別
- a:調用成員變量
- this.成員變量 調用本類的成員變量,也可以調用父類的成員變量
- super.成員變量 調用父類的成員變量
- b:調用構造方法
- this(...) 調用本類的構造方法
- super(...) 調用父類的構造方法
- c:調用成員方法
- this.成員方法 調用本類的成員方法,也可以調用父類的方法
- super.成員方法 調用父類的成員方法
- a:調用成員變量
class Demo4_Extends {
public static void main(String[] args) {
Son s = new Son();
s.print();
}
}
class Father {
int num1 = 10;
int num2 = 30;
}
class Son extends Father {
int num2 = 20;
public void print() {
System.out.println(this.num1); //this既可以調用本類的,也可以調用父類的(本類沒有的情況下)
System.out.println(this.num2); //就近原則,子類有就不用父類的了
System.out.println(super.num2);
}
}
運行結果
繼承中構造方法的關系
- 子類中所有的構造方法默認都會訪問父類中空參數的構造方法
-
因為子類會繼承父類中的數據,可能還會使用父類的數據。
-
所以,子類初始化之前,一定要先完成父類數據的初始化。
-
其實:
- 每一個構造方法的第一條語句默認都是:super() Object類最頂層的父類。
-
class Demo5_Extends {
public static void main(String[] args) {
Son s = new Son();
}
}
class Father extends Object {
public Father() {
super();
System.out.println("Father 的構造方法");
}
}
class Son extends Father {
public Son() {
super(); //這是一條語句,如果不寫,系統會默認加上,用來訪問父類中的空參構造
System.out.println("Son 的構造方法");
}
}
繼承中構造方法的注意事項
class Demo6_Extends {
public static void main(String[] args) {
Son s1 = new Son();
System.out.println("--------------------");
Son s2 = new Son("張三",23);
}
}
class Father {
private String name; //姓名
private int age; //年齡
public Father() { //空參構造
System.out.println("Father 空參構造");
}
public Father(String name,int age) { //有參構造
this.name = name;
this.age = age;
System.out.println("Father 有參構造");
}
public void setName(String name) { //設置姓名
this.name = name;
}
public String getName() { //獲取姓名
return name;
}
public void setAge(int age) { //設置年齡
this.age = age;
}
public int getAge() { //獲取年齡
return age;
}
}
class Son extends Father {
public Son() { //空參構造
System.out.println("Son 空參構造");
}
public Son(String name,int age) { //有參構造
System.out.println("Son 有參構造");
}
}
運行結果
System.out.println
上一行隱藏了Super();
/*
* 父類沒有無參構造方法,子類怎么辦?
* super解決
* this解決
* 注意事項
* super(…)或者this(….)必須出現在構造方法的第一條語句上
*/
class Demo6_Extends {
public static void main(String[] args) {
Son s1 = new Son();
System.out.println(s1.getName() + "..." + s1.getAge());
System.out.println("--------------------");
Son s2 = new Son("張三",23);
System.out.println(s2.getName() + "..." + s2.getAge());
}
}
class Father {
private String name; //姓名
private int age; //年齡
public Father() { //空參構造
System.out.println("Father 空參構造");
}
public Father(String name,int age) { //有參構造
this.name = name;
this.age = age;
System.out.println("Father 有參構造");
}
public void setName(String name) { //設置姓名
this.name = name;
}
public String getName() { //獲取姓名
return name;
}
public void setAge(int age) { //設置年齡
this.age = age;
}
public int getAge() { //獲取年齡
return age;
}
}
class Son extends Father {
public Son() { //空參構造
this("王五",25); //本類中的構造方法
//super("李四",24); //調用父類中的構造方法
System.out.println("Son 空參構造");
}
public Son(String name,int age) { //有參構造
super(name,age);
System.out.println("Son 有參構造");
}
}
this和super只能存在一個
運行結果
看程序寫結果1
class Fu{
public int num = 10;
public Fu(){
System.out.println("fu");
}
}
class Zi extends Fu{
public int num = 20;
public Zi(){
System.out.println("zi");
}
public void show(){
int num = 30;
System.out.println(num);
System.out.println(this.num);
System.out.println(super.num);
}
}
class Test1_Extends {
public static void main(String[] args) {
Zi z = new Zi();
z.show();
}
}
結果為 fu zi 30 20 10
不要忘了public Zi() { 隱藏的Super()
看程序寫結果2
class Fu {
static {
System.out.println("靜態代碼塊Fu");
}
{
System.out.println("構造代碼塊Fu");
}
public Fu() {
System.out.println("構造方法Fu");
}
}
class Zi extends Fu {
static {
System.out.println("靜態代碼塊Zi");
}
{
System.out.println("構造代碼塊Zi");
}
public Zi() {
System.out.println("構造方法Zi");
}
}
class Test2_Extends {
public static void main(String[] args) {
Zi z = new Zi();
}
}
結果為
靜態代碼塊Fu
靜態代碼塊Zi
構造代碼塊Fu
構造方法Fu
構造代碼塊Zi
構造方法Zi
1.jvm調用了main方法,main先進棧
2.遇到Zi z = new Zi();會先將Fu.class和Zi.class分別加載進內存,再創建對象,當Fu.class加載進內存父類的靜態代碼塊會隨着Fu.class一起加載,當Zi.class加載進內存子類的靜態代碼塊會隨着Zi.class一起加載,
3.走Zi類的構造方法,因為java中是分層初始化的,先初始化父類,再初始化子類,所以先走的父類構造,但是在執行父類構造時,發現父類有構造代碼塊,構造代碼塊是優先於構造方法執行的
4.Fu類初始化結束,子類初始化
繼承中成員方法關系
class Demo7_Extends {
public static void main(String[] args) {
Son s = new Son();
s.print();
s.method();
}
}
/*
* a:不同名的方法
* b:同名的方法
*/
class Father {
public void print() {
System.out.println("Fu print");
}
}
class Son extends Father {
public void method() {
System.out.println("Zi Method");
}
public void print() {
super.print(); //super可以調用父類的同名成員方法
System.out.println("Zi print");
}
}
運行結果為
Fu print
Zi print
Zi Method
方法重寫概述及其應用
- 重寫:子父類出現了一模一樣的方法
- 方法重寫的應用:
- 當子類需要父類的功能,而功能主體子類有自己特有內容時,可以重寫父類中的方法。這樣,即沿襲了父類的功能,又定義了子類特有的內容。
定義一個手機類
class Demo7_Phone {
public static void main(String[] args) {
Ios8 i = new Ios8();
i.siri();
i.call();
}
}
/*
ios7系統 siri speak English
ios8系統 siri 說中文
*/
class Ios7 {
public void call() {
System.out.println("打電話");
}
public void siri() {
System.out.println("speak English");
}
}
class Ios8 extends Ios7 {
public void siri() {
System.out.println("說中文");
super.siri(); //保留原來的,不需要的話注釋掉即可
}
}
- 方法重寫注意事項
-
a:父類中私有方法不能被重寫
- 因為父類私有方法子類根本就無法繼承
-
b:子類重寫父類方法時,訪問權限不能更低
- 最好就一致
-
c:父類靜態方法,子類也必須通過靜態方法進行重寫
- 其實這個算不上方法重寫,但是現象確實如此,至於為什么算不上方法重寫,多態中我會講解(靜態只能覆蓋靜態)
-
子類重寫父類方法的時候,最好聲明一模一樣。
-
使用繼承后的學生和老師案例
class Test4_Person {
public static void main(String[] args) {
Student s1 = new Student();
s1.setName("張三");
s1.setAge(23);
System.out.println(s1.getName() + "..." + s1.getAge());
s1.eat();
s1.study();
System.out.println("------------------");
Student s2 = new Student("李四",24);
System.out.println(s2.getName() + "..." + s2.getAge());
s2.eat();
s2.study();
}
}
/*
* 使用繼承后的學生和老師案例
*/
class Person {
private String name; //姓名
private int age; //年齡
public Person() {} //空參構造
public Person(String name,int age) { //有參構造
this.name = name;
this.age = age;
}
public void setName(String name) { //設置姓名
this.name = name;
}
public String getName() { //獲取姓名
return name;
}
public void setAge(int age) { //設置年齡
this.age = age;
}
public int getAge() { //獲取年齡
return age;
}
public void eat() { //吃飯
System.out.println(name + "吃飯");
}
}
class Student extends Person {
public Student() {} //空參構造
public Student(String name,int age) {
super(name,age);
}
public void study() {
System.out.println(this.getName() + "學習");
//直接getName()或super.getName()也行
}
}
class Teacher extends Person {
public Teacher() {} //空參構造
public Teacher(String name,int age) {
super(name,age);
}
public void teach() {
System.out.println(this.getName() + "講課");
//直接getName()或super.getName()也行
}
}
貓狗案例分析,實現及測試
class Demo5_Animal {
public static void main(String[] args) {
Cat c1 = new Cat("白",4);
System.out.println(c1.getColor()+" "+c1.getLeg());
c1.eat();
c1.catchMouse();
Dog d1 = new Dog("黑",4);
System.out.println(d1.getColor()+" "+d1.getLeg());
d1.eat();
d1.lookHouse();
}
}
/*
* 貓狗案例繼承版
* 屬性:毛的顏色,腿的個數
* 行為:吃飯
* 貓特有行為:抓老鼠catchMouse
* 狗特有行為:看家lookHome
*/
class Animal {
private String color;
private int leg;
public Animal(){
}
public Animal(String color,int leg){
this.color = color;
this.leg = leg;
}
public void setColor(String color){
this.color = color;
}
public void setLeg(int leg){
this.leg = leg;
}
public String getColor(){
return color;
}
public int getLeg(){
return leg;
}
public void eat(){
System.out.println("吃飯");
}
}
class Cat extends Animal{
public Cat(){
}
public Cat(String color,int leg){
super(color,leg);
}
public void eat(){
System.out.println("貓吃魚");
}
public void catchMouse(){
System.out.println("抓老鼠");
}
}
class Dog extends Animal{
public Dog(){
}
public Dog(String color,int leg){
super(color,leg);
}
public void eat(){
System.out.println("狗吃屎");
}
public void lookHouse(){
System.out.println("看家");
}
}
final關鍵字
- final修飾特點
-
修飾類,類不能被繼承
final class Father {
與class Son extends Father {
會報錯: 無法從最終Father進行繼承 -
修飾變量,變量就變成了常量,只能被賦值一次
final int NUM = 10;
與NUM = 20
會報錯: 無法為最終變量NUM分配值
//常量命名規范,如果是一個單詞,所有字母大寫,如果是多個單詞,每個單詞都大寫,中間用下划線隔開如MAX_VALUE -
修飾方法,方法不能被重寫
-
class Demo2_Final {
public static void main(String[] args) {
final int num = 10;
//num = 20; //基本類型,是值不能被改變
System.out.println(num);
final Person p = new Person("張三",23);
//p = new Person("李四",24);// 引用類型,是地址值不能被改變
p.setName("李四");//對象中的屬性可以改變
p.setAge(24);
System.out.println(p.getName() + "..." + p.getAge());
}
}
class Person {
private String name; //姓名
private int age; //年齡
public Person()
public Person(String name,int age)
public void setName(String name)
public String getName()
public void setAge(int age)
public int getAge()
}
final修飾變量的初始化時機
- 顯示初始化
- 在對象構造完畢前即可
兩種只能選擇一種
class Demo3_Final {
public static void main(String[] args) {
Demo d = new Demo();
d.print();
}
}
class Demo {
//final int num = 10; //顯示初始化
public Demo() {
num = 10;//在對象構造完畢前
}
public void print() {
System.out.println(num);
}
}