面向对象1(super、this)

目录

 

1.局部变量和成员变量

2.参数传递

2.1基本数据类型作为参数传递

2.2 引用类型作为参数传递

3.面向对象的三个特征

3.1 封装

3.2 继承

成员变量

成员方法

3.3 多态

前提:

定义格式:

缺点

优点

4.this关键字

通过this实现构造方法的相互引用

5.super关键字


1. 局部变量和成员变量

 局部变量成员变量
位置方法中或者{ }中类中
内存中的位置栈内存的方法中堆内存的对象中
生命周期随着方法的运行而出现在栈中;随着方法的弹栈而消失随着对象的出现而出现在堆中;随着对象的消失而从堆中消失
初始化

无默认初始值;

需手动赋值才可用

可不用初始化

所有默认的初始化

2. 参数传递

2.1 基本数据类型作为参数传递

class Demo{
    public static void main(String[] args){
        int x=4;
        show(x);
        System.out.println("x="+x);
}

    public static void show(int x){
        x=5;
    }
}

运行结果:

分析:

将基本类型变量来那个x空间中的值复制了一份传递给调用的方法show();

在show()方法中的x接收到了复制的值,再对x进行操作,只会影响到show中的x;

当show()执行完弹栈后,程序又回到main()执行;

main()中的x还是原来的值。

2.2 引用类型作为参数传递

public class DemoTest {
	int x;
    public static void main(String[] args){
        DemoTest d=new DemoTest();
        d.x=5;
        show(d);
        System.out.println("x="+d.x);
}

    public static void show(DemoTest d){
        d.x=5;
    }
}

运行结果:

分析:

将引用变量空间中的内存地址(引用)复制了一份传递给了show()的d引用变量;

这时两个引用同时指向堆中的同一个对象

当执行了shou()中的d.x=6时,会根据d所持有的引用找到堆中的对象,并将其x属性的值改为6,show()弹栈。

由于两个引用指向同一个对象,不管那个引用改变了引用所指向的对象中的值,其他引用再次使用都是改变后的值。

3. 面向对象的三个特征

3.1 封装

  • 表现:方法就是一个最基本的封装体,类也是一个封装体,用private修饰的变量也是封装体;
  • 好处:提高了代码的复用性;隐藏了具体实现细节,需对外提供可访问的方式(setter()/getter());提高了安全性

3.2 继承

通过继承可以是多种事物之间形成一种关系体系。

关键字:extends

子类在继承父类后,会自动拥有的父类的成员

  • 好处:提高了代码的复用率,提高软件开发率;让类与类之间出现了关系提供了多态的前提

注意:

  • Java中只支持单继承;
  • 多个类可以继承一个类;
  • Java中可多层继承;
  • Java中,子类和父类是一种相对的概念。

成员变量

当子父类出现同名成员变量时,若子类要访问父类中的成员变量,需使用关键字super;

  • super表示当前对象中包含的父类对象空间的引用。

当在程序中通过对象调用方法时:

  • 会先在子类中查找有没有对应的方法;
  • 若子类中存在,则执行子类中的方法;
  • 若子类中没有,则执行父类中响应的方法。

成员方法

override:重写、覆盖

  • 子类中出现与父类一模一样的方法
  • 用@Override标注
  • 子类覆盖父类的方法必须保证权限大于等于父类权限
  • 必须一模一样:方法名、参数列表
  • 弊端:类和类之间耦合度过高
  • 优点:提高改吗重用性,可维护性,是多态前提之一

所有的类都直接或间接继承了Object

overload:重载

  • 在同一个类中,多个方法名称相同,参数列表(个数、数据类型)不同。

3.3 多态

表示当同一个操作作用在不同对象上时,会有不同的语义,从而会产生不同的结果。

最终多态体现为:父类引用可指向子类对象

前提

  • 必须有子父类关系或者类实现接口的关系
  • 方法的重写
  • 父类引用指向子类对象

在使用多态后的父类引用变量调用方法时,会调用子类重写后的方法。(若多个子类重写,则调用的是各个子类自己重写的方法(动态绑定))

表现方式

  1. 方法的重载(overload):同一个类中有多个同名的方法,但这些方法有着不同的参数(个数、类型、顺序),在编译时可以确定到底调用哪一个方法——编译时多态。重载可看做是一个类中的方法多态性。
  2. 方法的覆盖(override):子类可以覆盖父类的方法,因此同样的方法在子类和父类中会有着不同的表现形式。
    1. 基类的引用变量不止可以指向基类的实例对象,还可以指向子类的实例对象。
    2. 接口的引用变量也可以指向其实现类的实例对象。
    3. 程序运行的方法在运行期才动态绑定(绑定:将一个方法调用和一个方法主体连接到一起 )。
    4. 引用变量所指向的具体实例对象(内存里正在运行的那个对象)的方法,而不是引用变量的类型中定义的方法。
    5. 通过这种动态绑定的方法实现了多态。
    6. 只有在运行时再能确定调用那个方法,所以这个多态叫做——运行时多态
class Base{
	public Base() {
		g();
	}
	public void f() {
		System.out.println("Base f()");
	}
	public void g() {
		System.out.println("Base g()");
	}
}

class Derived extends Base{
	public void f() {
		System.out.println("Derived f()");
	}
	public void g() {
		System.out.println("Derived g()");
	}
}

public class DBTest{
	public static void main(String[] args) {
		Base b=new Derived();
		b.f();
		b.g();		
	}
}

运行结果

Base b=new Derived();会调用Base类的构造方法。而在Base类的构造方法中执行了g()。由于多态,此时会调用子类Deriverd的g(),而非Base类的g(),因此会输出第一个Derived g()。

定义格式

父类    变量名 = new     子类();

抽象类    变量名 = new    抽象类子类();

接口    变量名 = new    接口实现类();

当子父类出现同名的成员变量时,多态调用该变量时,编译运行看左边(父类);

  • Dad d=new Son();
  • d.num;    调用的是父类的成员变量
  • 因为Java中成员变量没有重写的概念
class Base{
	public int i=1;
}

class Derived extends Base{
	public int i=2;
}

public class DBTest{
	public static void main(String[] args) {
		Base b=new Derived();
		System.out.println(b.i);
	}
}

运行结果

1

当子父类出现同名的成员方法时,多态调用该方法时,编译看左边,运行看右边(子类);

  • 编译时会检查左边父类中有无对应的成员

当子父类出现同名的静态方法时,多态调用该方法,编译运行看左边(父类)(相当于类名调用,所以也是看父类);

  • 都看左边

缺点

无法直接访问子类的特有成员,需向下转型。

优点

继承的优点(可维护性);

可扩展性。

4. this关键字

可在成员变量上加上this,来区别成员变量和局部变量

class Person{
	private int age;
	public int getAge() {
		return this.age;
	}
	public void setAge(int age) {
		this.age=age;
	}
}

public class DemoTest{
	public static void main(String[] args) {
		Person p=new Person();
		p.setAge(30);
		System.out.println(p.getAge());
	}
}

运行结果:

分析:

  1. 先执行main(),压栈,执行其中的Person p=new Person();
  2. 在堆内存中开辟空间,并为其分配内存地址0x1234,成员变量默认初始化(age=0);
  3. 执行p.setAge(30);
  4. 调用setAge(int age),将30赋值给setAge()中的age变量
  5. 执行this.age=age,将age变量的值30赋值给成员变量this.age;
  6. setAge()执行完,弹栈,回到main()执行输出语句System.out.println(),输出p对象中的age值。

若局部变量名和成员变量名相同,在使用时采用的是就近原则

通过this实现构造方法的相互引用

this(参数列表)

package ObjectOriented;

class Person{
	private int age;
	private String name;
	Person(){
		
	}
	Person(String nm){
		name=nm;
	}
	Person(int a,String nm){
		this(nm);
		age=a;
	}
}

public class DemoTest{
	public static void main(String[] args) {
		Person p=new Person(30,"张三");
	}
}

分析:

  1. 先执行main(),压栈,执行其中的new Person(30,"张三");
  2. 堆内存中开辟空间,并未其分类内存地址0x33,成员变量默认初始化(name=null,age=0);
  3. 拥有两个参数的构造方法(Person(int,String))压栈,在这个构造方法中有一个隐式的this,指向堆中的那个对象
    1. 因为构造方法是给对象初始化的,那个对象调用这个构造方法
  4. 由于Person(int,String)中使用了this(nm),构造方法Person(String)压栈,并将“张三”传给nm。
  5. 在Person(String)同样也有this执行0x33.执行name=nm,将“张三”赋值给成员name。
  6. Person(String)弹栈
  7. Person(int,String)将30赋值给成员age,弹栈;
  8. Person对象在内存中构建完成,并将0x33赋值给main()中的p引用变量。

5. super关键字

子类中的所有构造方法的第一行由默认的隐式的super();语句;

  • 原因:因为子类继承了父类的内容,所以创建对象时,必须先要看父类是如何对其内容进行初始化的

当父类中没有空参构造方法时,子类的构造方法必须有显示的super语句,指定要访问的父类有参的构造方法;

若第一行用this调用了本类的其他构造方法,则此时无super();

  • 因为它们都在第一行,初始化动作要先执行
  • super,this不共存

父类构造方法中也有隐式的super

  • 只要是构造方法,第一行默认都是super();

父类的父类是Object,它是所有对象的父类。

由于有super()调用父类无参构造方法,所以父类的构造方法既可以给自己的对象初始化,也可以给子类的对象初始化化

super(arg);——也可以有参数。

如果子类构造方法的第一行没有调用父类的构造方法,则会默认调用副类的无参构造(有的话),也可用super(arg)在子类构造方法中的第一行显式调用父类的有参构造。

父类的构造方法会先执行,因为先初始化父类中的成员变量,自诶后面可能要用到。

  • 访问父类的构造函数:可以使用 super() 函数访问父类的构造函数,从而委托父类完成一些初始化的工作。
  • 访问父类的成员:如果子类重写了父类的中某个方法的实现,可以通过使用super 关键字来引用父类的方法实现。
     

 

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值