天天看点

黑马程序员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();
	}
}
           

继续阅读