码迷,mamicode.com
首页 > 编程语言 > 详细

黑马程序员(Java)----面向对象(中)

时间:2015-08-07 07:06:10      阅读:150      评论:0      收藏:0      [点我收藏+]

标签:java   继承   

------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------

3.1 继承的概述

    继承是面向对象的一个重要特征。当多个类中存在相同属性和行为时,将这些内容抽取到单独一个类中,那么多个类无需再定义这些属性和行为,只要继那个类即可。这时,多个类可以称为子类,单独的这个类称为父类或者超类。

    继承的好处:

    1、提高了代码的复用性

    2、提高了代码的维护性

    3、让类与类之间产生了关系,是多态的前提

    继承的坏处:

    类与类产生了关系,其实也是继承的一个弊端,因为类的耦合性增强了。


    继承的用法:Java中使用extends关键字来表示子类继承父类,使用格式:class 子类名 extends 父类名。示例:

class Person {
	public void eat() {
		System.out.println("吃饭");
	}
	
	public void sleep() {
		System.out.println("睡觉");
	}
}

class Student extends Person {}

class Teacher extends Person {}

class ExtendsDemo {
	public static void main(String[] args) {
		Student s = new Student();
		s.eat();
		s.sleep();
		System.out.println("-------------");
		
		Teacher t = new Teacher();
		t.eat();
		t.sleep();
	}
}
    运行结果:

3.2 继承的特点

    1、Java只支持单继承,不支持多继承  。

    2、Java支持多层继承(继承体系)。例如:class Son extends Father { }; class Father extends GrandFather { }

3.3 继承的注意事项

    1、子类只能继承父类所有非私有的成员(成员方法和成员变量)

    2、子类不能继承父类的构造方法,但是可以通过super关键字去访问父类构造方法。

    3、不要为了部分功能而去继承

3.4 继承中子父类成员的关系

3.4.1 super关键字

    this和super的用法很相似,this代表本类对象的引用,super代表父类的内存空间的标识(可以理解为父类引用,可以操作父类的成员)。当本类的成员变量和局部变量同名用this来区分,当子父类中的成员变量同名用super来区分。

    this调用的是当前类中的成员变量、构造方法和成员方法,super调用的是父类中的成员变量、构造方法和成员方法,并且调用构造方法时,该语句都必须是构造方法的第一句。

3.4.2 子父类中变量的特点

    如果子类中出现非私有的同名成员变量时,子类要访问本类中的成员变量,用this。子类要访问父类中的同名成员变量,用super。this代表的是本类对象的引用。super代表的是父类对象的引用。示例:

class Father {
	public int num = 10;
}

class Son extends Father {
	public int num = 20;
	
	public void show() {
		int num = 30;
		System.out.println(num);
		System.out.println(this.num);
		System.out.println(super.num);
	}
}

class ExtendsDemo5 {
	public static void main(String[] args) {
		Son s = new Son();
		s.show();
	}
}
    运行结果:

技术分享

3.4.3 子父类中构造方法的特点

    子类中所有的构造方法默认都会访问父类中空参数的构造方法,也就是说,在对子类对象进行初始化时,会先运行父类的构造方法。因为子类的构造函数默认第一行会有一条隐式的语句super(),super()会访问父类中空参数的构造函数,而且子类中所有的构造函数默认第一行都是super()。示例:

class Father {
	int age;

	public Father() {
		System.out.println("Father的无参构造方法");
	}
	
	public Father(String name) {
		System.out.println("Father的带参构造方法");
	}
}
class Son extends Father {
	public Son() {
		//super();  系统会默认在这个地方加上super();
		System.out.println("Son的无参构造方法");
	}
	
	public Son(String name) {
		//super();  系统会默认在这个地方加上super();
		System.out.println("Son的带参构造方法");
	}
}	

class ExtendsDemo6 {
	public static void main(String[] args) {
		Son s = new Son();
		System.out.println("------------");
		Son s2 = new Son("锤子");
	}
}
    运行结果:

技术分享
    

    如果父类中没有无参的构造方法时,该怎么解决呢?

    如果父类中没有无参的构造方法,可以通过使用super关键字去显示的调用父类的带参构造方法;也可以通过this关键字去调用本类的其他构造方法,但是必须保证子类中有一个构造方法访问了父类的构造方法。因为在子类对象进行初始化时,必须先初始化父类。示例:

class Father {
	public Father(String name) {
		System.out.println("Father的带参构造方法");
	}
}
class Son extends Father {
	public Son() {
		super("名字");
		System.out.println("Son的无参构造方法");
	}
	
	public Son(String name) {
		this();
		System.out.println("Son的带参构造方法---"+name);
	}
}
class ExtendsDemo7 {
	public static void main(String[] args) {
		Son s = new Son();
		System.out.println("----------------");
		Son ss = new Son("锤子");
	}
}


    运行结果:

技术分享

3.4.4 子父类中成员方法的特点

    建立一个子类的对象,该对象可以分别调用父类和子类中方法。当子父类中的方法同名时,子类的对象调用该方法时,会执行子类中的该方法,而不是父类中的该方法,这种情况叫方法的覆盖,也叫重写(override)。

    1、怎么判断是否为重写(override)呢?

    1)、具有父子关系的两个类。

    2)、父类和子类各有一个函数,这另个函数的的定义(返回值类型、函数名、参数列表)完全相同。

class Phone {
	public void call(String name) {
		System.out.println("给"+name+"打电话");
	}
}

 class NewPhone extends Phone {
	public void call(String name) {
		//System.out.println("给"+name+"打电话");
		super.call(name);
		System.out.println("可以边打电话边看图片了");
	}
}

class ExtendsDemo9 {
	public static void main(String[] args) {
		NewPhone np = new NewPhone();
		np.call("锤子哥");
	}
}

    运行结果:

技术分享

    2、方法重写(override)的注意事项

    1)、父类中私有方法不能被重写,因为父类私有方法子类根本就无法继承

    2)、子类重写父类方法时,访问权限不能低于父类该方法的权限,最好一致。

    3)、父类静态方法,子类也必须通过静态方法进行重写

    3、比较方法重载(overload)和重写(override)

    1)、重载的两个函数存在于同一个类中;重写的两个函数存在于具有父子关系的两个类中。 

    2)、重载的函数名相同,参数列表(参数类型和参数数量)不同;重写的返回值类型、函数名和参数列表都相同。 

     示例:需求:创建一个动物的类,成员变量有name,age,color,构造方法包括有参和无参两种,成员方法有getXxx(),setXxx(),eat()。然后让Cat继承它,并复写eat()方法。

class Animal{
	private String name;
	private int age;
	private String color;
	
	public Animal(){}
	public Animal(String name,int age,String color){
		this.name = name;
		this.age = age;
		this.color = color;
	}
	
	public void eat(){
		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;
	}
	public void setColor(String color){
		this.color = color;
	}
	public String getColor(){
		return color;
	}
}
class Cat extends Animal{
	public Cat(){}
	public Cat(String name,int age,String color){
		super(name,age,color);
	}
	public void eat(){
		System.out.println("我在吃东西");
	}
}
class ExtendsTest5{
	public static void main(String[] args){
		//方式1
		Cat c1 = new Cat();
		c1.setName("小花");
		c1.setAge(2);
		c1.setColor("黑白");
		System.out.println(c1.getName()+"---"+c1.getAge()+"---"+c1.getColor());
		c1.eat();
		//方式2
		Cat c2 = new Cat("小花",2,"黑白");
		System.out.println(c1.getName()+"---"+c1.getAge()+"---"+c1.getColor());
		c2.eat();
	}
}
    运行结果:

技术分享

3.5 子类实例化过程

    以Zi z = new Fu(20)为例

    1、把Zi.class文件加载到内存,由于Zi类继承Fu类,所以也将Fu.class文件加载到内存。
    2、在栈内存为s开辟空间。
    3、在堆内存为学生对象开辟空间。
    4、给Zi类的成员变量age进行默认初始化(int类型的变量默认值为0)。
    5、给Zi类的age成员变量在父类中进行显示初始化(int age = 1)。
    6、通过父类的构造方法给age成员变量进行初始化(int age = 2)。
    7、在子类中进行显示初始化(int age = 3)。
    8、通过子类的构造方法给age进行初始化(int age = 4)。    
    9、对象构造完毕,把地址赋值给z变量。

验证:

class Fu{
	int age = 1;
	public Fu(){
		System.out.println(age);
		age = 2;
		System.out.println(age);
	}
}
class Zi extends Fu{
	int age = 3;
	public Zi(){
		System.out.println(age);
		age = 4;
		System.out.println(age);
	}
}
class Test{
	public static void main(String[] args){
		Zi z = new Zi();
	}
}

    运行结果:

技术分享

3.6 final关键字

    1、final翻译成汉语就是“最终”的意思,可以修饰类、变量和函数。 

     被final修饰的类不可以被继承。

    被final修饰的方法不可以被复写。

    被final修饰的变量(成员变量和局部变量)是一个常量,且只能被赋值一次。

    内部类只能访问被final修饰的局部变量。

    2、常量的书写规范

    所有字母大写。

     如果由多个单词组成,单词间通过”_“连接。 

    3、final修饰局部变量

/*
    面试题:final修饰局部变量的问题
    基本类型:基本类型的值不能发生改变。
    引用类型:引用类型的地址值不能发生改变,但是,该对象的堆内存的值是可以改变的。
*/
class Student {
	int age = 10;
}

class FinalTest {
	public static void main(String[] args) {
		//局部变量是基本数据类型
		int x = 10;
		x = 100;
		System.out.println(x);
		final int y = 10;
		//无法为最终变量y分配值
		//y = 100;
		System.out.println(y);
		System.out.println("--------------");
		
		//局部变量是引用数据类型
		Student s = new Student();
		System.out.println(s.age);
		s.age = 100;
		System.out.println(s.age);
		System.out.println("--------------");
		
		final Student ss = new Student();
		System.out.println(ss.age);
		ss.age = 100;//对象引用所指的堆内存中的值是可以改变的
		System.out.println(ss.age);
		
		//重新分配内存空间
		//无法为最终变量ss分配值
		//ss = new Student();
	}
}
    运行结果:

技术分享

    结论:基本类型:基本类型的值不能发生改变。

    引用类型:引用类型的地址值不能发生改变,但是,该对象的堆内存的值是可以改变的。


版权声明:本文为博主原创文章,未经博主允许不得转载。

黑马程序员(Java)----面向对象(中)

标签:java   继承   

原文地址:http://blog.csdn.net/xw_classmate/article/details/47274695

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!