重写
含义
在Java中,子类可继承父类中的方法,而不需要重新编写相同的方法。但有时子类并不想原封不动地继承父类的方法,而是想作一定的修改,这就需要采用方法的重写。方法重写又称方法覆盖。
重写与重载的异同点
相同点
都是作用在方法上
不同点
重载时作用在同一个类中,多个方法名相同,参数列表不同(方法签名不同)而采用的方式
重写是作用在不同类,该类继承于需要修改方法的父类.
区别:
重载是在同一个类中,方法名相同,参数列表不同
重写是作用在两个有继承关系的子类中,方法签名相同
需要重写的原因
在一些业务实现过程中,子类存在从父类中继承的功能,但子类要实现的功能与父类不同所以我们需要重写该功能,以满足我们的业务需求
重写(在子类中才能重写)
重写的方法:与普通方法相同,但是方法名和参数列表要与父类中相同
重写的方法的调用顺序
子类对象在调用这个功能的使用,如果有重写方法,就调用重写方法如果没有则调用父类的方法
public class OverrideDemo {
public static void main(String[] args) {
//创建一个子类的实例(对象)
Son son=new Son();
//使用子类的重载方法
son.word();
}
}
//父类
class Dad{
private int money=1250;
//父类的方法 如果加上static则无法被子类继承
public void words(){
System.out.println("我是父类的方法");
}
}
//子类 父类继承子类
class Son extends Dad{
//在父类被static修饰后,该方法不是重写父类的方法,而是创建了一个新方法
public void word(){
System.out.println("我是子类的方法");
}
}
**注意:**父类中,方法被static被修饰,则子类无法继承.如果子类中有相同的方法签名,则该方法是子类新建方法,并非对父类方法的重写.
super关键字
super与this的区别
this:代指当前创建的对象
- 调用本类中其他构造器
- 必须放在构造器首行
- this([参数列表])//参数是列表匹配本类中的其他构造器
- 区分同名变量(局部变量与成员变量)的问题
- this.变量名 代指当前创建对象的变量即成员变量
super:指代父类对象
- 调用父类构造器
- 默认调用父类的空构造器//所以在写javaBean的时候要求必须有一个空构造器
- 调用父类的其他构造器需要显式调用super([参数列表]),参数列表匹配父类构造器的参数列表
- 与this相同,必须放在构造器的首行
- this与super在同个构造器中,不能同时来调用其他构造器
- 区分同名变量问题(子类和父类)
- 局部 子类成员 父类成员同名的时候调用局部变量直接写该变量名|方法名(),调用子类变量的时候写this.变量名|this.方法名(),调用父类成员的时候super.变量名|super.方法名()
- 注意:调用构造方法与调用普通的方法不一样,采用super.变量名|super(参数列表)
如何设置父类中属性值的两种方式:
- 用设置器和获取器来设置和访问父类中的属性
- 采用通过构造器给父类的属性赋值,其具体经过如下:子类在创建对象时,调用子类构造器,子类构造器,我们可以子类构造器首行调用父类构造器传入参数,将参数传入到父类构造器中,进而实现对父类属性的赋值
public class Supper01 {
public static void main(String[] args) {
//先执行子类的无参构造,在执行父类的无参构造
Son son1=new Son();
//先执行子类的有参构造,在把值传给父类的有参构造
Son son2=new Son("小吴");
}
}
//父类
class Dad{
//父类成员变量
String name;
//父类成员方法
public void study(){
System.out.println("父亲在学习");
}
//父类构造器
public Dad() {
System.out.println("父类空构造");
}
public Dad(String name) {
this.name = name;
System.out.println("父类带参构造"+this.name);//这里的name是指代当前父类的成员
}
}
//子类 继承父类
class Son extends Dad{
//子类成员变量
String name;
//子类成员方法
@Override
public void study() {
System.out.println("儿子在学习.覆盖了父亲在学习");
}
//子类构造器1
public Son() {
System.out.println("子类无参构造器");
}
//子类构造器2
public Son(String name) {
super(name);//把变量传给父类的构造
System.out.println("子类有参构造器");
}
}
final关键字 最终
记住以下三点:
-
被final修饰的变量为常量
- 变量的数据类型如果是基本数据类型:存储的数据值不能改变
- 变量的数据类型如果是引用数据类型:存储的地址值不会改变,但是对象内存中的属性可以改变
-
被final修饰的方法不能被重写
public class Final01 { public static void main(String[] args) { DadOne dad=new DadOne(); SonOne son=new SonOne(); son.eat(); } } class DadOne{ int a=5; public static void eat(){ System.out.println("父类的吃"); } } class SonOne extends DadOne{ public static void eat(){//方法签名与父类一致,但是不是重写,因为该方法中在父类中final修饰过,此为新方法 System.out.println("子类的吃"); } }
以上的代码不会报错,
-
被final修饰的类不能被继承(俗称太监类)
public class Final01 {
public static void main(String[] args) {
DadOne dad=new DadOne();
SonOne son=new SonOne();
}
}
final class DadOne{
int a=5;
}
class SonOne extends DadOne{//此行会报错
}
Object类(所有的类的最基础的类,相当于源头)
所以类的父亲,java中的所有类都会直接或间接继承来自Object类
如果没有显式继承其他类,默认继承自Object类
toString方法
-
toString()把对象的内容以字符串的形式展示
源码:
public String toString() { return getClass().getName() + "@" + Integer.toHexString(hashCode()); }
在打印一个对象的引用的时候,打印对象的地址,默认打印的是这个对象调用了toString 方法的返回值,根据需要可对toString方法进行重写.
-
equal方法:
equals两种情况
- 如使用是Object类中的equal()方法中比较是对象的地址
- 如有对equal()方法重写,则比较就是方法重写的内容.如String.euqals("");
/*
判断两个用户是否是同一个用户,判断条件为 用户名和密码 相同,并输出用户的信息
思路:重写equals方法,判断其中 用户名和密码,重写toString输出用户的信息
*/public class UserNamePassword {
public static void main(String[] args) {
UserPassword u1=new UserPassword("小翁","123456");
UserPassword u2=new UserPassword("xaiaong","56152");
UserPassword u3=new UserPassword("小翁","123456");
String a="525";
System.out.println(u1);
System.out.println(u2);
System.out.println(u3);
System.out.println(u1.equals(u2));
System.out.println(u1.equals(u3));
System.out.println(u1.equals(525));
System.out.println(u1.user.equals("小翁"));
}
}
class UserPassword{
public String user;
public String password;
public UserPassword() {
super();
}
public UserPassword(String user, String password) {
super();
this.user = user;
this.password = password;
}
//重写toString方法
@Override
public String toString() {
return user+password;
}
//重写euqual方法
@Override
public boolean equals(Object obj) {
if(this==obj){
return true;
}else{
if(obj instanceof UserPassword){
UserPassword u=(UserPassword)obj;
if(this.user==u.user){
return true;
}else{
return false;
}
}
return false;
}
}
}
多态
面向对象的三大特征
封装:隐藏内部的实现细节,对外提供公共的方法方式.私有是封装的一种具体的表现形式
继承:子类一旦继承父类,有权实现父类的内容
多态:一种事物的多种形态|多种表现方式
多态的前提
必须是类的继承或是接口的实现
多态的最终体现
父类的引用指向子类的对象
假设Person是父类,Study是子类
Person p=new Study();
多态重写方法的调用顺序
如果子类和父类中同时有重写方法,多态调用是子类中的重写方法,如没有则直接调用父类的方法.
注意:父类引用对子类的新增内容不可见
多态的编译与运行
- 成员变量
- 编译看父类|看左边|看类型
- 成员方法
- 编译看父类,运行看子类
- 编译看左边,运行看右边
- 编译看类型,运行找对象
public class Shy {
public static void main(String[] args) {
Pig pigOne=new Pig();
Aniaml pigTwo=new Pig();
//测试
//子类引用指向子类对象 成员变量与成员方法都可以使用
System.out.println(pigOne.name);
pigTwo.eat();
/*父类引用指向子类对象
成员变量:不可以直接使用子类对象的属性
成员方法:如果有子类重写方法,则直接使用子类重写的方法
如果子类中没有该方法,而父类中有此方法,则直接使用父类的方法
注意:如果该变量不可以无法使用子类中的新增内容
*/
System.out.println(pigTwo.name+"===");
// System.out.println(pigTwo.name);
pigTwo.eat();
}
}
class Aniaml{
//成员变量
public String name="动物";
private int age;
//成员方法
public void eat(){
System.out.println("我喜欢吃");
}
//构造函数
public Aniaml() {
super();
}
public Aniaml(String name, int age) {
super();
this.name = name;
this.age = age;
}
}
//子类
class Pig extends Aniaml{
String name="小猪";
int age;
public Pig(){
super();
}
public Pig(String name,int age){
super(name,age);
}
@Override
public void eat() {
System.out.println("猪吃猪");
}
}
注意事项
子类引用指向子类对象 ,成员变量与成员方法都可以使用如下种形式:
//Person是父类,Study是子类
Person p=new Study();
成员变量:不可以直接使用子类对象的属性
成员方法:如果有子类重写方法,则直接使用子类重写的方法
如果子类中没有该方法,而父类中有此方法,则直接使用父类的方法
**注意:**如果该变量不可以无法使用子类中的新增内容
子类型转换
向上类型转换
就是多态的使用
向下类型转换
子类类型 引用 = (子类类型)父类类型的数据;
判断是否为该父类的子类,用instanceof判断
注意:向下转型后,就可以使用子类新增内容
public class Shy02 {
public static void main(String[] args) {
//孔子以孔子爹的面孔展现
//父类(孔子爹) 的引用 指向 子类对象(孔子)
//向上转型,从子类到父类
ConfuciusDad kzd=new Confucius();
kzd.teache();
//向下转型,父类转到子类,才能使用子类的新增内容
Confucius kz=(Confucius)kzd;
kz.play();
//向下转型,父类引用可以转到任意子类的类型,但是也可能不是我们想要的
/* Brother kzb=(Brother)kzd;
kzb.play(); */
//向下类型转换前,可以采用instanceof进行判断是否为我们想要的子类
if(kzd instanceof Confucius){//判断kzd是否是Confucius的一个实例(对象)返回boolean值
Confucius kzz=(Confucius)kzd;
kzz.play();
}
}
}
class ConfuciusDad{
public void teache(){
System.out.println("孔子爹---授课");
}
}
class Confucius extends ConfuciusDad{
public void teache(){
System.out.println("孔子---授课");
}
public void play(){
System.out.println("大话西游");
}
}
class Brother extends ConfuciusDad{
public void teache(){
System.out.println("孔子兄弟---授课");
}
public void play(){
System.out.println("LOL");
}
}
抽象
抽象类:被abstract修饰的类
抽象方法:别abstract修饰的方法
抽象方法:必须在抽象类中且必须在抽象类中
注意:
- 抽象类不能被实例化|不能创建对象
- 抽象方法要存在于抽象类中,抽象方法必须被重写
- 抽象类的使用
- 具体子类:重写所用的抽象方法+按需新增
- 抽象子类:按需重写抽象方法+按需新增
- 一个抽象方法一旦被重写过,就不需要再次被重写
- 抽象列中可以存在普通方法,可以存在抽象方法
- abstract不能和private,final,static,native一起使用
父类:
- 具体父类
- 可以创建父类对象,同时知道父类中的内容如何定义可以定义具体的父类
- 抽象父类
- 不想要能够直接创造父类对象
- 父类中的方法体不知道如何实现
示例:
定义抽象类
//定义一个抽象类
public abstract class Develop {
//定义两个抽象类 work sleep
public abstract void work();
public abstract void slepp();
}
定义具体子类
//具体的子类必须全部实现 继承的抽象类中的方法
public class Java extends Develop{
@Override
public void work() {
System.out.println("java攻城狮在工作");
}
@Override
public void slepp() {
System.out.println("java攻城狮在睡觉");
}
public void huo(){
System.out.println("java攻城狮在接私活");
}
}
定义抽象父类,并定义具体子类
//具体的子类必须全部实现 继承的抽象类中的方法
//如果有一个没有实现,则应该把此类也定义成抽象类
public abstract class Web extends Develop{
@Override
public void work() {
System.out.println("Web工程师在工作");
}
}
class Demo extends Web{
//实现了上面未实现的方法
@Override
public void slepp() {
System.out.println("web工程师也在休息");
}
}
测试代码
public class Test {
public static void main(String[] args) {
Java java=new Java();
java.work();
java.slepp();
java.huo();
Demo d=new Demo();
d.slepp();
d.work();
}
}