extends
关键字
目录
概要
- Java中的继承实现方式与执行顺序
本文主要探究如何使用Java中的继承(
extends
)?以及子父类中,static{}
、{}
和构造器执行顺序。
- 子父类的equals重写注意事项
Java中的继承实现方式与执行顺序
A:
/*
* @ProjectName: 编程学习
* @Copyright: 2018 HangZhou xiazhaoyang Dev, Ltd. All Right Reserved.
* @address: http://xiazhaoyang.tech
* @date: 2018/9/17 22:28
* @email: xiazhaoyang@live.com
* @description: 本内容仅限于编程技术学习使用,转发请注明出处.
*/
package com.capsule.chapter.extend;
import java.util.Date;
/**
* <p>
*
* </p>
*
* @author xiazhaoyang
* @version V1.0
* @date 2018/9/17 22:28
* @modificationHistory=========================逻辑或功能性重大变更记录
* @modify By: {修改人} 2018/9/17
* @modify reason: {方法名}:{原因}
* ...
*/
public class A {
public A() {
System.out.println("Class A");
}
{
System.out.println("{} A");
overrideMe("{}");
}
static{
System.out.println("static A");
overrideMeStatic("static");
}
public void overrideMe(String area){
System.out.println("overrideMe A - " + area);
}
public static void overrideMeStatic(String area){
System.out.println("overrideMeStatic A - " + area);
}
public static void main(String[] args) {
new A();
//static A
//overrideMeStatic A - static
//{} A
//overrideMe A - {}
//Class A
}
}
分析
- 类在初始化时,方法块
{}
、静态方法块static{}
、构造器className()
的执行顺序依次是:static{} > {} > className() - 静态方法只能在静态方法块中执行,所以静态方法的执行顺序和静态方法块一样,是最高的(除非静态方法快中并没有使用该静态方法)。
B:
/*
* @ProjectName: 编程学习
* @Copyright: 2018 HangZhou xiazhaoyang Dev, Ltd. All Right Reserved.
* @address: http://xiazhaoyang.tech
* @date: 2018/9/17 22:29
* @email: xiazhaoyang@live.com
* @description: 本内容仅限于编程技术学习使用,转发请注明出处.
*/
package com.capsule.chapter.extend;
/**
* <p>
*
* </p>
*
* @author xiazhaoyang
* @version V1.0
* @date 2018/9/17 22:29
* @modificationHistory=========================逻辑或功能性重大变更记录
* @modify By: {修改人} 2018/9/17
* @modify reason: {方法名}:{原因}
* ...
*/
public class B extends A{
public B() {
System.out.println("Class B");
}
{
//方法快中无论什么方法都可以执行
System.out.println("{} B");
isStatic();
notStatic();
}
static{
//静态方法块中只能执行静态方法
System.out.println("static B");
//notStatic(); 报错
isStatic();//不报错,使用的是静态方法
}
public static void isStatic(){
System.out.println("is static method B");
}
public void notStatic(){
System.out.println("not static method B");
}
public static void overrideMe(){
overrideMeStatic("static method B");//父类静态方法
System.out.println("overrideMe B");
}
public static void main(String[] args) {
B b = new B();
b.overrideMe();
B.overrideMe();
//---父类static{}
//static A
//overrideMeStatic A - static
//---子类static{}
//static B
//is static method B
//---父类方法块
//{} A
//overrideMe A - {}
//---父类构造器
//Class A
//---子类方法块
//{} B
//is static method B
//not static method B
//---子类构造器
//Class B
//--- 实例方法调用
//overrideMeStatic A - static method B
//overrideMe B
//--- 子类静态方法调用
//overrideMeStatic A - static method B
//overrideMe B
}
}
分析
- 子类初始化时,
父类static{}和其中的静态方法
>子类static{}和其中的静态方法
>父类方法块{}
>父类构造方法
>子类方法块
>子类构造器
-
static{}
方法块执行优先级最高(父>子) - 单个类中,方法块调用在类初始化构造器之前,子父类中,子类方法块的执行在父类构造器方法之后执行
Java中的继承实现方式与执行顺序 注意事项
要么为继承而设计,并提供文档说明,要么就禁止继承
- 继承对于final变量域的修改
Super:
/*
* @ProjectName: 编程学习
* @Copyright: 2018 HangZhou Yiyuery Dev, Ltd. All Right Reserved.
* @address: http://xiazhaoyang.tech
* @date: 2018/9/12 08:50
* @email: xiazhaoyang@live.com
* @description: 本内容仅限于编程技术学习使用,转发请注明出处.
*/
package com.capsule.chapter.extend;
/**
* <p>
*
* </p>
*
* @author xiazhaoyang
* @version V1.0
* @date 2018/9/12 08:50
* @modificationHistory=========================逻辑或功能性重大变更记录
* @modify By: {修改人} 2018/9/12
* @modify reason: {方法名}:{原因}
* ...
*/
public class Super {
public Super() {
overrideMe();
}
public void overrideMe(){
System.out.println("Super overrideMe!");
}
}
Sub:
/*
* @ProjectName: 编程学习
* @Copyright: 2018 HangZhou Yiyuery Dev, Ltd. All Right Reserved.
* @address: http://xiazhaoyang.tech
* @date: 2018/9/12 08:52
* @email: xiazhaoyang@live.com
* @description: 本内容仅限于编程技术学习使用,转发请注明出处.
*/
package com.capsule.chapter.extend;
import java.util.Date;
/**
* <p>
*
* </p>
*
* @author xiazhaoyang
* @version V1.0
* @date 2018/9/12 08:52
* @modificationHistory=========================逻辑或功能性重大变更记录
* @modify By: {修改人} 2018/9/12
* @modify reason: {方法名}:{原因}
* ...
*/
public class Sub extends Super{
private final Date date;
Sub(){
date = new Date();
}
@Override
public void overrideMe(){
System.out.println(date);
}
public static void main(String[] args) {
Sub sub = new Sub();
sub.overrideMe();
//null
//Wed Sep 12 08:55:57 CST 2018
}
}
继承之后,子类实例化之前会先执行被重载的父类方法overrideMe(),此时子类的实例化尚未完成,静态块也未执行,所以虽然是final修饰的字段,date变量仍然是null,实例化时打印null,实例化之后打印复制后的新时间。
继承父类,子类重写equals方法如何正确使用instance of
基类 Lombok自动生成
/*
* @ProjectName: 编程学习
* @Copyright: 2018 HangZhou Yiyuery Dev., Ltd. All Right Reserved.
* @address: http://xiazhaoyang.tech
* @date: 2018/7/29 22:24
* @email: xiazhaoyang@live.com
* @description: 本内容仅限于编程技术学习使用,转发请注明出处.
*/
package com.example.chapter3.extend;
/**
* <p>
*
* </p>
*
* @author xiachaoyang
* @version V1.0
* @date 2018年11月02日 10:11
* @modificationHistory=========================逻辑或功能性重大变更记录
* @modify By: {修改人} 2018年11月02日
* @modify reason: {方法名}:{原因}
* ...
*/
public class EqualsSuper {
private Integer count;
private String superName;
public EqualsSuper() {
}
public Integer getCount() {
return this.count;
}
public String getSuperName() {
return this.superName;
}
public void setCount(Integer count) {
this.count = count;
}
public void setSuperName(String superName) {
this.superName = superName;
}
public boolean equals(Object o) {
if (o == this) return true;
if (!(o instanceof EqualsSuper)) return false;
final EqualsSuper other = (EqualsSuper) o;
//此处o针对的是实际类型,如果是EqualsSub, other.canEqual 进入的是子类的canEqual方法
//判断equalsSuper.equals(equalsSub) return other instanceof EqualsSub;
//(Object) this) 指向 EqualsSuper
// new EqualsSuper() instanceof EqualsSub; //false
if (!other.canEqual((Object) this)) return false;
final Object this$count = this.count;
final Object other$count = other.count;
if (this$count == null ? other$count != null : !this$count.equals(other$count)) return false;
final Object this$superName = this.superName;
final Object other$superName = other.superName;
if (this$superName == null ? other$superName != null : !this$superName.equals(other$superName)) return false;
return true;
}
public int hashCode() {
final int PRIME = 59;
int result = 1;
final Object $count = this.count;
result = result * PRIME + ($count == null ? 0 : $count.hashCode());
final Object $superName = this.superName;
result = result * PRIME + ($superName == null ? 0 : $superName.hashCode());
return result;
}
public boolean canEqual(Object other) {
return other instanceof EqualsSuper;
}
public String toString() {
return "com.example.chapter3.extend.EqualsSuper(count=" + this.count + ", superName=" + this.superName + ")";
}
}
子类 Lombok自动生成
/*
* @ProjectName: 编程学习
* @Copyright: 2018 HangZhou Yiyuery Dev., Ltd. All Right Reserved.
* @address: http://xiazhaoyang.tech
* @date: 2018/7/29 22:24
* @email: xiazhaoyang@live.com
* @description: 本内容仅限于编程技术学习使用,转发请注明出处.
*/
package com.example.chapter3.extend;
/**
* <p>
*
* </p>
*
* @author xiachaoyang
* @version V1.0
* @date 2018年11月02日 10:12
* @modificationHistory=========================逻辑或功能性重大变更记录
* @modify By: {修改人} 2018年11月02日
* @modify reason: {方法名}:{原因}
* ...
*/
public class EqualsSub extends EqualsSuper{
private String subName;
public EqualsSub() {
}
public String getSubName() {
return this.subName;
}
public void setSubName(String subName) {
this.subName = subName;
}
public boolean equals(Object o) {
if (o == this) return true;
if (!(o instanceof EqualsSub)) return false;
final EqualsSub other = (EqualsSub) o;
if (!other.canEqual((Object) this)) return false;
final Object this$subName = this.subName;
final Object other$subName = other.subName;
if (this$subName == null ? other$subName != null : !this$subName.equals(other$subName)) return false;
return true;
}
public int hashCode() {
final int PRIME = 59;
int result = 1;
final Object $subName = this.subName;
result = result * PRIME + ($subName == null ? 0 : $subName.hashCode());
return result;
}
public boolean canEqual(Object other) {
return other instanceof EqualsSub;
}
public String toString() {
return "com.example.chapter3.extend.EqualsSub(subName=" + this.subName + ")";
}
public static void main(String[] args) {
EqualsSub equalsSub = new EqualsSub();
equalsSub.setSubName("sub2");
equalsSub.setCount(2);
equalsSub.setSuperName("super2");
EqualsSuper equalsSuper = new EqualsSuper();
equalsSuper.setCount(2);
equalsSuper.setSuperName("super2");
System.out.println(equalsSub.equals(equalsSuper));//false
System.out.println(equalsSuper.equals(equalsSub));//false
}
}
备注
equals
方法通过lombok插件delombok生成,可见lombok插件在自动生成eauls方法时不会去考虑父类属性。
写法调整 V1 子父类Equals判断
EqualsSub
public boolean equals(Object o) {
if (o == this) return true;
if (o instanceof EqualsSub){
final EqualsSub other = (EqualsSub) o;
if (!other.canEqual((Object) this)) return false;
final Object this$subName = this.subName;
final Object other$subName = other.subName;
if (this$subName == null ? other$subName != null : !this$subName.equals(other$subName)) return false;
}else if(o instanceof EqualsSuper){
return super.equals(o);
}
return false;
}
//...
public static void main(String[] args) {
EqualsSub equalsSub = new EqualsSub();
equalsSub.setSubName("sub2");
equalsSub.setCount(2);
equalsSub.setSuperName("super2");
EqualsSuper equalsSuper = new EqualsSuper();
equalsSuper.setCount(2);
equalsSuper.setSuperName("super2");
System.out.println(equalsSub.equals(equalsSuper));//true
System.out.println(equalsSuper.equals(equalsSub));//false
}
子父类 instance of 比较区别
new EqualsSuper() instanceof EqualsSub //false
new EqualsSub() instanceof EqualsSuper //true
写法调整 V2 IDEA 默认实现方式
EqualsSuper
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof EqualsSuper)) return false;
EqualsSuper that = (EqualsSuper) o;
return Objects.equals(count, that.count) &&
Objects.equals(superName, that.superName);
}
@Override
public int hashCode() {
return Objects.hash(count, superName);
}
EqualsSub
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof EqualsSub)) return false;
if (!super.equals(o)) return false;
EqualsSub equalsSub = (EqualsSub) o;
return Objects.equals(subName, equalsSub.subName);
}
@Override
public int hashCode() {
return Objects.hash(super.hashCode(), subName);
}
public static void main(String[] args) {
EqualsSub equalsSub = new EqualsSub();
equalsSub.setSubName("sub2");
equalsSub.setCount(2);
equalsSub.setSuperName("super2");
EqualsSuper equalsSuper = new EqualsSuper();
equalsSuper.setCount(2);
equalsSuper.setSuperName("super2");
System.out.println(equalsSub.equals(equalsSuper));//false
System.out.println(equalsSuper.equals(equalsSub));//true
}
写法调整 V2 + V1 调整判断一致性
EqualsSub
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o instanceof EqualsSub){
if (!super.equals(o)) return false;
EqualsSub equalsSub = (EqualsSub) o;
return Objects.equals(subName, equalsSub.subName);
}else if(o instanceof EqualsSuper){
return super.equals(o);
}
return false;
}
//...
public static void main(String[] args) {
EqualsSub equalsSub = new EqualsSub();
equalsSub.setSubName("sub2");
equalsSub.setCount(2);
equalsSub.setSuperName("super2");
EqualsSuper equalsSuper = new EqualsSuper();
equalsSuper.setCount(2);
equalsSuper.setSuperName("super2");
System.out.println(equalsSub.equals(equalsSuper));//true
System.out.println(equalsSuper.equals(equalsSub));//true
}
总结
- 比对lombok和idea模板两种比较方法,各有优点和缺点
- lombok不对父类进行属性比较,idea模板不具有一致性,只支持Super.equals(Sub)
微信公众号
扫码关注或搜索架构探险之道
获取最新文章,不积跬步无以至千里,坚持每周一更,坚持技术分享_ !