天天看點

黑馬程式員java學習日記——面向對象(三)

------- android教育訓練、java教育訓練、期待與您交流! ----------

一、      抽象類

  (1)抽象:把多個類中的共性的内容進行抽取,抽取後就能形成一個繼承體系。但是,在今天的案例中,方法的聲明相同,方法體不同,這樣的抽取後,在父類中定義的時候,是不能寫方法體的,這樣的方法要想被java識别,就必須被标記為抽象的。如果一個類有抽象方法,那麼該類肯定是抽象類。反之,抽象類中不一定有抽象方法。

     抽象類的由來:

多個對象都具備相同的功能,但是功能具體内容有所不同,那麼在抽取過程中,隻抽取了功能定義,并未抽取功能主體,那麼隻有功能聲明,沒有功能主體的方法稱為抽象方法。

例如:狼和狗都有吼叫的方法,可是吼叫内容是不一樣的。是以抽象出來的犬科雖然有吼叫功能,但是并不明确吼叫的細節。

(2)格式:

    抽象方法隻有方法聲明,沒有方法體,定義在抽象類中。

     格式:修飾符 abstract 傳回值類型 函數名(參數清單);

(2)好處:

       A:抽象類中可以有成員變量和非抽象方法,也可以實作代碼的複用。

       B:抽象類強制要求繼承他的子類必須完成某些功能。

    (3)成員特點:

       A:構造方法

           抽象類有構造方法,但是本身不能被執行個體化。

           它的構造方法用于子類執行個體化使用。

       B:成員變量

           抽象類既可以有成員變量,也可以有成員常量。

       C:成員方法

           抽象類既可以抽象方法,也可以有非抽象方法。

     代碼示例:

abstract class Animal
{
	private String name;
	public final int x = 10;
	public Animal()
	{
		System.out.println("animal");
	}
	public Animal(String name)
	{
		this.name = name;
	}
	public void setName(String name)
	{
		this.name = name;
	}
	public String getName()
	{
		return name;
	}
	public void show()
	{
		System.out.println("今天天氣不錯,适合學習");
	}
	public abstract void method();//定義抽象方法
}
class Dog extends Animal
{
	public Dog()
	{	
		super();
		System.out.println("dog");
	}
	public Dog(String name)
	{
		super(name);
	}
	public void show()
	{
		System.out.println("今天天氣不錯,适合郊遊");
	}
	public void method()
	{
		System.out.println("dog method");
	}
}
class AbstractDemo2 
{
	public static void main(String[] args) 
	{
		//建立對象
		//Animal a = new Animal();
		Dog d = new Dog();
		System.out.println(d.getName());
		Dog d2 = new Dog("小白");
		System.out.println(d2.getName());
		d2.show();
		d2.method();
	}
}
           

(4)使用:

       當一個類繼承一個抽象類的時候

           要麼重寫抽象類的所有抽象方法。

           要麼本身是一個抽象類。

    (5)抽象類的注意事項

       A:抽象類沒有構造方法,那麼有什麼用?

           有,用于子類執行個體化使用。

       B:是否有非抽象方法?如果沒有抽象方法類為什麼要定義為抽象類?

           有,提高代碼複用性。

           沒有抽象方法的抽象類就是為了不讓他能建立對象。

       C:abstract不能和哪些關鍵系并存。

           private:私有的功能,子類是不能重寫的。而abstract是要求子類重寫的。

           fianl:最終的意思,子類不能重寫。而abstract是要求子類重寫的。

           static:靜态的意思,它是跟類相關的。而我們研究的是對象間的關系。

                 靜态的東西,可以通過類名調用,但是,抽象的方法,用類名調用沒有實際意義。

       修飾關鍵字:

           預設修飾符,private,public -- 成員變量private,成員方法public

           fianl:最終的,可以修飾類,成員變量,成員方法

           static:讓成員多了一種調用方式。可以修飾成員。

           abstract:修飾類,修飾方法,表示是抽象。

           組合使用:

           一般格式:

              權限修飾符+static+final+成員變量/方法

       代碼示例:

/*
	老師示例
		具體事物:基礎班老師,就業班老師
		共性:姓名,年齡,講課。
	
根據我們學過的面向對象知識,我們就可以如下分析:
		定義一個老師類,然後,分别讓基礎班老師和就業班老師繼承老師類。

		如何定義一個老師類呢,就是分析基礎班老師和就業班老師的共性内容:

		老師類:
			成員變量:姓名,年齡
			成員方法:講課 因為每個老師講課的内容不一樣,是以,我們定義為抽象方法。

		基礎班老師:
			重寫講課方法
			輸出老師的資訊。

		就業班老師:
			重寫講課方法
			輸出老師的資訊。
*/
abstract class Teacher
{
	private String name;
	private int age;

	public Teacher(){}

	public Teacher(String name,int age)
	{
		this.name = name;
		this.age = age;
	}

	public String getName()
	{
		return name;
	}

	public int getAge()
	{
		return age;
	}

	//抽象的講課方法
	public abstract void teach();

	public void printMessage()
	{
		System.out.println(name+"***"+age);
	}
}

class BaseTeacher extends Teacher
{
	public BaseTeacher(String name,int age)
	{
		super(name,age);
	}

	public void teach()
	{
		System.out.println("基礎班老師講JavaSE");
	}

	/*
	public void printMessage()
	{
		System.out.println(getName()+"***"+getAge());
	}
	*/
}

class WorkTeacher extends Teacher
{
	public WorkTeacher(String name,int age)
	{
		super(name,age);
	}

	public void teach()
	{
		System.out.println("就業班老師講JavaEE");
	}
}

class TeacherDemo 
{
	public static void main(String[] args) 
	{
		BaseTeacher bt = new BaseTeacher("林青霞",25);
		bt.teach();
		bt.printMessage();

		WorkTeacher wt = new WorkTeacher("郭德綱",38);
		wt.teach();
		wt.printMessage();

		//使用多态
		Teacher t = new BaseTeacher("劉姐",18);
		t.teach();
		t.printMessage();

		t = new WorkTeacher("芙蓉姐姐",20);
		t.teach();
		t.printMessage();
	}
}
           

二、接口

  (1)接口:當一個抽象類中的方法都是抽象的時候,(并且都是成員常量的時候的。)java提供了一個新的表示形式,那就是接口。

(2)好處:

       A:接口是對外暴露的規則(比如:USB,電腦内部的插槽,CPU的針孔)

       B:接口是功能的擴充

       C:接口降低了程式的耦合性

           低耦合:類與類之間的關系

           高内聚:類本身的能力

       D:接口可以用來多實作

       E:類與接口之間是實作關系,而且類可以繼承一個類的同時實作多個接口

       F:接口與接口之間可以有繼承關系

(3)成員特點:

       A:成員變量

           成員變量都是常量,因為有預設修飾符:public static final

       B:成員方法

           成員方法都是抽象的,因為有預設修飾符:public abstract

       建議,每次自己寫接口的時候,盡量把修飾符自己寫上。

(4)類,接口互相間的關系:

       A:類與類

           繼承關系,java隻支援類的單繼承,但是可以多重(層)繼承。

       B:類與接口

           實作關系,可以單實作,也可以多實作。

           還可以在繼承一個類的同時,實作多個接口。

       C:接口與接口

           繼承關系,可以單繼承,也可以多繼承。

           如果一個類實作一個接口,就必須實作該接口及其父接口的所有抽象方法。

       代碼示例:

interface Inter//定義一個接口
{
	public abstract void show();//方法是抽象的
}
interface Inter2//定義第二個接口,兩個方法都是抽象的
{
	public abstract void method();
	public abstract void show();
}
interface Inter3 extends Inter,Inter2//第三個接口繼承了前兩個接口
{
	public abstract void function();
}
class Fu //預設有個extends Object
{
}
class Demo extends Fu implements Inter,Inter2//繼承Fu類并實作了前兩個接口
{
	public void show()//複寫show方法
	{
		System.out.println("demo show");
	}
	public void method()//複寫method方法
	{
		System.out.println("demo method");
	}
}
           

三、抽象類和接口的差別:

    (A)成員差別:

       抽象類:

           構造方法

           成員變量:可以是變量,也可以是常量。

           成員方法:可以是抽象方法,也可以是非抽象方法。

       接口:

           成員變量:隻能是常量。預設修飾符:public static final

           成員方法:隻能是抽象方法。預設修飾符:public abstract

    (2)類隻能單繼承

       而接口可以多繼承。接口的出現避免了java的單繼承的局限性。

    (3)抽象類被繼承,類中定義的是繼承體系的共性内容。

       接口被實作,接口中定義的是體系的擴充内容。

    (4)設計了解不同:

       抽象類被繼承,展現的是一種:"is a" 的關系

       接口被實作,展現的是一種:"like a" 的關系

代碼示例:

abstract class Person//抽象類
{
	private String name;
	private int 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 abstract void eat();//定義抽象方法
}
abstract class Player extends Person
{
	public abstract void study();//抽象方法 
}
abstract class Coach extends Person
{
	public abstract void teach();//抽象方法
}
interface StudyEnglish//接口
{
	public abstract void studyEnglish();//接口中的抽象方法
}
class PingPongStu extends Player implements StudyEnglish
{
	public void studyEnglish()//複寫抽象方法
	{
		System.out.println("乒乓運動員學英語");
	}
	public void study()//複寫抽象方法
	{
		System.out.println("乒乓運動員學習乒乓");
	}
	public void eat()//複寫抽象方法
	{
		System.out.println("乒乓運動員吃乒乓");
	}
}
class PingPongCoach extends Coach implements StudyEnglish
{
	public void studyEnglish()//複寫抽象方法
	{
		System.out.println("乒乓教練學英語");
	}
	public void teach()//複寫抽象方法
	{
		System.out.println("乒乓教練教學員學乒乓");
	}
	public void eat()//複寫抽象方法
	{
		System.out.println("乒乓教練吃乒乓乒乓");
	}
}
class BasketStu extends Player 
{
	public void study()//複寫抽象方法
	{
		System.out.println("籃球運動員學打籃球");
	}
	public void eat()//複寫抽象方法
	{
		System.out.println("籃球運動員吃籃球");
	}
}
class BasketCoach extends Coach 
{
	public void teach()//複寫抽象方法
	{
		System.out.println("籃球教練教學員學打籃球");
	}
	public void eat()//複寫抽象方法
	{
		System.out.println("籃球教練吃籃球");
	}
}
class PersonDemo
{
	public static void main(String[] args)
	{
		PingPongStu pps = new PingPongStu();
		pps.setName("王浩");
		pps.setAge(44);
		System.out.println("姓名是:"+pps.getName()+",年齡是:"+pps.getAge());
		pps.study();
		pps.eat();
		pps.studyEnglish();
		System.out.println("************************");
		BasketStu bs = new BasketStu();
		bs.setName("姚明");
		bs.setAge(50);
		System.out.println("姓名是:"+bs.getName()+",年齡是:"+bs.getAge());
		bs.study();
		bs.eat();
		System.out.println("************************");
		PingPongCoach ppc = new PingPongCoach();
		ppc.setName("乒乓劉教練");
		ppc.setAge(36);
		System.out.println("姓名是:"+ppc.getName()+",年齡是:"+ppc.getAge());
		ppc.teach();
		ppc.eat();
		ppc.studyEnglish();
		System.out.println("************************");
		BasketCoach bc = new BasketCoach();
		bc.setName("籃球張教練");
		bc.setAge(25);
		System.out.println("姓名是:"+bc.getName()+",年齡是:"+bc.getAge());
		bc.teach();
		bc.eat();
	}
}
           

四、Object類的使用

    Object:類Object是類層次結構的根類。每個類都使用Object作為超類。

    Object類中我們要掌握的功能:

       A:public String toString()

           傳回該對象的字元串表示。建議所有子類都重寫此方法。

           如果沒有重寫,預設的結果是:

              getClass().getName() + '@' + Integer.toHexString(hashCode())

              類名@哈希值的十六進制

              public static String toHexString(int i):把i按照十六進制的資料傳回。

           為什麼要重寫呢?

              因為位址值的顯示對我們來說,沒有意義。

              為了讓顯示的效果有意義一些,重寫此方法。

         代碼示例:

class Student extends Object
{
	private String name;

	public Student(){}

	public void setName(String name)
	{
		this.name = name;
	}

	public String getName()
	{
		return name;
	}

	//重寫方法
	public String toString()
	{
		//成員變量的組成:多個成員變量用,隔開。
		//"name:"+name+",age:"+age;
		return "name:"+name;
	}
}

class ObjectDemo
{
	public static void main(String[] args)
	{
		//建立對象
		Student s = new Student();
		s.setName("林青霞");
		//[email protected]
		//其實在用輸出語句輸出一個對象的名稱的時候,其實是用對象調用了toString()方法而已。
		System.out.println(s);
		System.out.println(s.toString()); //類@十六進制的hashCode()

		//hashCode方法
		System.out.println(s.hashCode()); //4067003 -- int

		System.out.println(Integer.toHexString(4067003)); //3e0ebb
	}
}
		B:public int hashCode()
			傳回該對象的哈希碼值。
		C:finalize()
			當垃圾回收器确定不存在對該對象的更多引用時,由對象的垃圾回收器調用此方法。
		D:Class getClass():反射的時候講。
			傳回的是該類的位元組碼檔案對象的類檔案。
		E:public boolean equals(Object obj)
			訓示其他某個對象是否與此對象"相等"。
            如果類沒有重寫equals方法,那麼它比的還是位址值。
       代碼示例:
   class Student
{
	private String name;
	private int age;
	public Student(){}
	public Student(String name,int age)
	{
		this.name = name;
		this.age = age;
	}
	//重寫equals方法
	public boolean equals(Object obj)//重寫的是Object類中的equals方法
	{
		//為了提高程式的效率
		if(this == obj)
		{
			return true;
		}
		//為了提高程式健壯性
		if(!(obj instanceof Student))
		{
			return false;
		}
		Student s = (Student)obj; //向下轉型
		//這個if語句可以使用三元運算符改進
		//下邊equals是String類中重寫Object類中equals之後的
                return this.name.equals(s.name) && this.age == s.age;
	}
}
class Demo
{
}
class ObjectDemo3 
{
	public static void main(String[] args) 
	{
		Student s1 = new Student("李建峰",18);
		Student s2 = new Student("李建峰",18);
		Student s3 = new Student("張學友",20);
		System.out.println(s1.equals(s2));
		System.out.println(s1.equals(s3));
		//自己跟自己比
		System.out.println(s1.equals(s1));
		Demo d = new Demo();
		//ClassCastException
		System.out.println(s1.equals(d));
	}
}
           

五、内部類

1、内部類定義:

    将一個類定義在另一個類的裡面,對裡面那個類就稱為内部類(内置類,嵌套類)。

2、通路特點:

    A:内部類可以直接通路外部類中的成員,包括私有成員

    B:外部類要通路内部類中的成員必須要建立内部類的對象

代碼示例:

class Outer
{
	private int num = 10;
	//成員内部類
	class Inner
	{
		public void show()
		{
			System.out.println("num:"+num);
		}
	}
	//成員方法
	public void method()
	{
		//建立對象
		Inner in = new Inner();
		in.show();
	}
}
class InnerDemo
{
	public static void main(String[] args)
	{
		//在外部使用
		Outer o = new Outer();
		o.method();		
		//注意格式:外部類.内部類 名字 = 外部類對象.内部類對象
		Outer.Inner oi = new Outer().new Inner();
		oi.show();
	}
}
           

3、内部類位置

    A:成員位置

          a:如果沒有被private或者static修飾。

             外部類.内部類 名字 = 外部類對象.内部類對象;

             舉例:

                 Outer.Inner oi = new Outer().new Inner();

                 oi.show();

          b:被private或者static修飾。

             如果被private修飾後,就不能再在除了外部類的其他類中使用。

             如果被static修飾,并且沒有被private修飾,使用方式如下:

             外部類.内部類 名字 = 外部類.内部類對象;

             舉例:

                 Outer.Inner oi = new Outer.Inner();

                 oi.show();

            代碼示例:

/*
	内部類被靜态修飾:
*/
class Outer
{
	private static int num = 10;

	static class Inner
	{
		public void show()
		{
			System.out.println("show:"+num);
		}

		public static void method()
		{
			System.out.println("method:"+num);
		}
	}
}
class InnerDemo3 
{
	public static void main(String[] args) 
	{
		//Outer.Inner oi = new Outer().new Inner();
		Outer.Inner oi = new Outer.Inner();
		oi.show();
		oi.method();
		//靜态的不想通過對象通路
		Outer.Inner.method();
	}
}
           

内部類被private修飾:

/*
    内部類被private修飾
*/
class Outer
{
	private int num = 10;
	private class Inner
	{
		public void show()
		{
			System.out.println("num:"+num);
		}
	}
	public void method()
	{
		Inner in = new Inner();
		in.show();
	}
}
class InnerDemo2 
{
	public static void main(String[] args) 
	{
		//内部類被private修飾後就不能再被使用
		//Outer.Inner oi = new Outer().new Inner();
		Outer o = new Outer();
		o.method();
	}
}
           

B:局部位置

          a:有名字

             按照普通的方式使用即可。

          b:沒有名字,匿名内部類(掌握)

             格式:

                 new 類或者接口()

                 {

                    重寫方法,或者自定義方法

                 };

                 其實這裡的本質是一個子類匿名對象。

             前提:外部存在着一個類或者接口。

内部類定義在局部位置:

      在外部類的方法中定義一個類。   

    為什麼局部内部類通路局部變量需要用final修飾呢?

      因為内部類在使用完畢後,可能在堆記憶體還存在呢,這個時候,它要的變量也要存在。

      如果沒用final修飾,變量就會從棧中消失。

      final修飾的内容在哪裡?

      方法區裡面有一個常量區。它的生命周期你可以想象成和static一樣。

代碼示例:

class Outer
{
	//private int num = 10;
	public void method()
	{
		final int num = 20;
		//局部位置
		class Inner
		{
			public void show()
			{
				System.out.println("show "+num);
			}
		}
		//建立對象
		Inner in = new Inner();
		in.show();
	}
}
class InnerDemo4 
{
	public static void main(String[] args) 
	{
		Outer o = new Outer();
		o.method();
	}
}
           

什麼時候使用匿名内部類呢?

通常在使用方法是接口類型參數,并該接口中的方法不超過三個時,可以将匿名内部類作為參數傳遞。

增強閱讀性。

匿名内部類的使用:

interface Inter
{
	public abstract void hello();
	public abstract void haha();
}
class Outer
{
	private int num = 10;
	public void method()
	{
		/*
		class Inner//内部類形式
		{
			public void show()
			{
				System.out.println("num:"+num);
			}
		}
		Inner in = new Inner();
		in.show();
		*/
		/*
		new Inter(){//匿名内部類
			public void hello()
			{
				System.out.println("hello");
			}
		};
		*/
		//怎麼調用呢?
		/*
		new Inter(){//匿名内部類調用方法
			public void hello()
			{
				System.out.println("hello");
			}
		}.hello();
		*/
		/*
		new Inter(){
			public void hello()
			{
				System.out.println("hello");
			}
			public void haha()
			{
				System.out.println("haha");
			}
		}.hello();
		new Inter(){
			public void hello()
			{
				System.out.println("hello");
			}
			public void haha()
			{
				System.out.println("haha");
			}
		}.haha();
		*/
		//假如隻是實作了接口的方法,那麼還可以這樣用
		Inter in = new Inter(){
			public void hello()
			{
				System.out.println("hello");
			}
			public void haha()
			{
				System.out.println("haha");
			}
		};
		in.hello();
		in.haha();
	}
}
class NiMingInnerDemo 
{
	public static void main(String[] args) 
	{
		Outer o = new Outer();
		o.method();
	}
}
           

繼續閱讀