从零开始的Java笔记04 - 面向对象

面向对象

  • 面向过程:需要实现功能时,每一个步骤都亲力亲为。
  • 面向对象:需要实现功能时,不关心过程,而是找一个已有该功能的人帮我做事。这个帮我做事的人就是对象。

类 class

  • 类是属性和行为的集合。
  • 属性是状态信息。
  • 行为是实现的方法。
  • 举个例子,用手机的图纸可以造出手机用来打电话,但光拿着图纸并不能打电话,得把图纸给转化成手机的实体,才能完成打电话的功能。
  • 这里的图纸就是类,手机就是对象。


创建对象

找啥对象啊,要对象自己new一个不就好了嘛。
类不能直接使用,要把类创建成对象才能使用。

  1. 导包。
    import 包名称.类名称;就完成了导包。在同一个包的情况下,无需导包。
    不过聪明的IDEA可以帮我们自动导包,比如用到ScannerRandom这些在java.util下的子类的时候,自动补全的时候便自动导包了。
    我感觉我快要被IDEA宠死了。

  2. 创建。
    类名称 对象名 = new 类名称(构造参数);这是一个基本的创建对象的语句。如果这个类里有无参构造方法,构造参数就可以不写啦。例:Student stu = new Student();

  3. 访问成员变量:
    对象名.成员变量名 例:stu.name。(当然,如果这个成员变量在类里是private修饰的,就不能直接这么访问了。)

  4. 访问成员方法:
    对象名.成员方法名(传入参数)

对象也可以作为方法的参数。由于是引用类型,当方法对对象内的内容进行操作时,地址在堆内存中的对象内容就会发生改变,而且不会因方法的出栈而变化。我是不是上一篇笔记写过类似的来着


三大特征 - extends继承

  • 在写子类时,在类名后写上extends 父类名便完成了继承。
  • 子类可以继承父类的所有内容。不过构造方法还是要新写的。如果父类的构造方法是有参的,那么子类写构造方法的时候也要先super(父类所需要的构造参数);
    相当于构造子类的时候会先构造一个父类。
  • 在构造方法中,可以使用super(); 或 super(参数); 来调用父类的无参或有参构造。
  • 在IDEA中,写完一个类的成员变量之后,可以按下Alt+Insert,选择Constructor,select none以自动生成无参构造方法(如果有父类,会自动生成起码能构造出父类对象的构造方法。)也可以在Constructor中全选成员变量以生成一个全参构造方法。
  • Java是单继承的。毕竟谁能有两个亲生的父亲呢。
  • 可以多级继承,也就是爷爷类(当然还是叫父类,间接父类。
  • 一个父类可以有多个子类。

this

访问本类内容。
this就是指当前实例,也就是当前调用这个变量或方法的对象。(好绕口)
再换句话说,谁在调用,谁就是this。
再再换句话说,this在类里可以被等效替换成这个类的对象名。
比如Student类创建了stu对象,那么在Student类里写上this.name,这里指的就是这位stu本身的name。严打校园恋爱!


super

this指的是自己本身,super就是指爹。就把super等效替换成父类的对象名称吧。当然这么说好不严谨哦。

  • 可以访问父类成员变量: super.父类变量名
  • 可以访问父类成员方法: super.父类方法名
  • 可以访问父类构造方法: super(父类构造方法需要的参数);

Override覆盖重写

  • 在继承关系中,子类的方法名与父类的方法名一样,参数列表也一样。

  • 因为直接叫重写说不定会跟重载搞混掉,那就叫覆盖重写吧,不然覆写也行。

  • 主要作用就是把父类的方法给覆盖掉,这时候如果调用子类的这个方法,运行的就是子类覆写的方法了。当然这时候可以super.方法名来调用父类的方法,就不用复制粘贴了。

  • 建议在重写的方法名上方加上一个@Override代表重写方法,虽然没有什么实际上的作用,但是可以作为保险,以及给别人看的时候可以帮助他人理解。(万一你比较健忘,这样也可以帮助自己理解)(毕竟程序员最烦的四件事:1.写使用手册,2.写注释,3.别人不写使用手册,4.别人不写注释)

一个设计原则

  • 对于已经投入使用的类,尽量不要进行修改,而是通过创建新的类,通过继承旧的类,重复利用共性内容,并且添加新内容或改动。

一些其他的注意事项:

  • 子类方法的返回值必须小于等于父类方法返回值的范围。
  • 子类方法的权限必须大于等于父类方法的权限。

这也太绕口了8,其实也不是很重要,反正这些东西绝大多数时候都相等,除了有个情况,啥情况我忘了,后面要是想起来了说不定会补上(


在IDEA里自动生成构造函数

  1. 按下Alt + Insert(最好选择成员变量的下方,因为会在光标位置生成代码) 在这里插入图片描述

  1. Enter 后,选择要构造的成员变量,可以使用Shift + 方向键来快速多选变量。 在这里插入图片描述

  1. 选择完后再回车,一个能调用父类全参构造+子类全参构造的代码块就生成了。三个步骤加起来也就一秒。 在这里插入图片描述
    哇!这也太快了吧。 不要再傻傻手动敲构造方法了。
    同样地,覆盖重写、toString()、equals()等方法也可以快速生成。

接口 interface

例: public interface 接口名(){...}
是一种引用数据类型。
最重要的就是抽象方法。
例:public abstract void 方法名();

在接口中,写方法可以省略public abstract,相当于编译器会帮你加上。

  • 因为有抽象方法,想要使用接口就要先创建接口的实现类。

  • 而由于一个类想要创建实例,它就不能是抽象类,当然也不能有任何抽象方法,所以类想要实现(implements)接口,就要覆盖重写接口中的所有抽象方法,也叫实现抽象方法。

  • 接口是一种公共的规范标准。 相当于是给接口的实现类约束了条件,“想要支持这个接口就得重写它的所有抽象方法。”
    一般来说,实现类的取名规范是接口名后加上Impl.
    例:public class MyInterfaceImpl() implements MyInterface{...}

  • 但实际上一个抽象类也可以继承接口,并且不实现其所有的抽象方法。


default

是一个修饰符。它可以解决接口升级(新增抽象方法)后,要修改每个实现类以实现新的抽象方法的问题。
格式:public default 返回值 方法名(参数列表){...}
这样,接口升级后,实现类也可以调用这个default方法。

  • 接口的默认方法可以被实现类直接调用,也可以被实现类覆盖重写。

static静态方法

与类类似地,接口中的方法用static修饰之后,可以直接通过接口名.静态方法名来调用静态方法。


三大特征 - 封装

  • 将类里的成员变量用private修饰后,只有本类的方法能够访问,而外部的类不能直接通过 实例名.成员变量名 来访问该变量。
  • 因此封装后,通常对每个成员变量(如果有需要)构建Getter/Setter,这样在外部类想访问对象的成员变量时,只用对象名.getXxxx();就能返回对应的成员变量。
  • 封装的好处:举例,可以通过在Getter/Setter中写判断条件,来得到限制输入范围的效果。
  • 同样地,使用private修饰方法名后,只有本类中可以访问该方法。这样的好处比如:如果类中的两个方法含有大量重复代码,可以将这些代码单独拿出列为一个方法,并且用private修饰,这样这个“私有”方法就不会被外部类调用。

三大特征 - 多态

编译看左边,运行看右边。

多态基于extends与implements。

先看多态是啥吧:
创建对象的时候,使用如下格式:
父类 对象名 = new 子类();
接口 对象名 = new 实现类();
是一个左父右子的形态。
这种一个对象有多种形态的形式,就是多态。
先举个例子吧:

  • 父类是宠物Pet,并且是一个抽象类。拥有一个抽象方法feed与一个成员变量name。 (为什么不用Animal因为我懒得打了)
public abstract class Pet(){
	String name;
	public abstract void feed();
}
  • 子类是Dog、Cat,继承父类并重写其抽象方法。
public class Dog() extends Pet(){
	@Override
	public void feed(){
	sout("吃了狗粮!");
	}
}
public class Cat() extends Pet(){
	@Override
	public void feed(){
	sout("吃了猫罐头!");
	}
}
  • 创建实例:
Pet dog = new Dog();
Pet cat = new Cat();

这个时候就相当于把Dog当做Pet来看待。这就是多态的体现。

多态使用的特点?

  • 对于成员变量:
    编译看左边,运行看左边。
    意思就是说:在调用实例的成员变量时,会先看父类有没有这个成员变量,如果有,则调用父类的这个成员变量,如果没有,则会报错。
    用上面的例子来说:当我访问dog.name的时候,会访问父类Pet的name变量。如果Pet里有一个name = “pet” ,dog里定义的name = “dog” , 最后访问dog.name的时候会得到pet。

  • 对于成员方法:
    编译看左边,运行看右边。
    意思就是说:调用实例的成员方法时,会先看父类有没有这个成员方法(编译看左边),如果有,则调用子类(创建实例时候的右边)的成员方法(运行看右边)。
    用上面的例子:dog.feed();会打印“吃了狗粮!”,调用cat.feed();会打印“吃了猫罐头!”
    注意:这样子就不能调用子类的特有方法了。因为编译看左边,如果编译器发现左边(父类)没有这个特有方法,就会报错。如果非要调用,需要对该对象进行强制类型向下转换。如:(Dog) dog. 这个形式和基本数据类型的强制转换是一样的。

有啥子用?
无论一个父类有多少个子类,只需要父类名 obj = new 子类名(); 就可以调用父类的公共方法。而且这些实例都是以父类的形式存在的。比如:往ArrayList中存放大量实例的时候,就可以通过ArrayList< Pet > 来存放Dog和Cat的实例了。
代码的灵活程度上升了!
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值