例6.4
//例6.4:显式使用super调用父类的构造方法
class AddClass {
private int x=0,y=0,z=0;
AddClass (int x) {
this.x=x;
}
AddClass (int x,int y) {
this(x);
this.y=y;
}
AddClass (int x,int y,int z) {
this(x,y);
this.z=z;
}
public int add() {
return x+y+z;
}
}
public class SonAddClass extends AddClass{
int a=0,b=0,c=0;
SonAddClass (int x) {
super(x); a=x+7;
}
SonAddClass (int x,int y){
super(x,y); a=x+5; b=y+5;
}
SonAddClass (int x, int y,int z){
super(x,y,z); a=x+4; b=y+4; c=z+4;
}//super(x,y,z)如果去掉会如何?
public int add() {
System.out.println("super:x+y+z="+super.add());
return a+b+c;
}
public static void main(String[] args){
SonAddClass p1=new SonAddClass (2,3,5);
SonAddClass p2=new SonAddClass (10,20);
SonAddClass p3=new SonAddClass (1);
System.out.println("a+b+c="+p1.add());
System.out.println("a+b="+p2.add());
System.out.println("a="+p3.add());
}
}
例6.5
//例6.5:隐式使用super调用父类的构造方法
class Pare {
int i=3;
Pare(){
System.out.println("call super()");
}
}
class Construct extends Pare {
int i = 10;
Construct() {
System.out.println("execute Construct()");
}
Construct(int num) {
this(); //如果去掉此句呢?
System.out.println("execute Construct(int)");
}
public static void main(String[] args) {
Construct ct = new Construct(9);
System.out.println(ct.i);
}
}
//输出:
执行顺序:
1.为子类对象分配内存空间,对域变量进行默认初始化。
2.绑定构造方法,将new对象中的参数传递给构造方法的形式参数。
3.调用this或super语句。
4.进行实例变量的显式初始化操作。
5.执行当前构造方法体中的程序代码。
通过对象引用的方法,创建两个类,这两个类中都包含另一个类的成员。
class FighterPlane {
String name;
int missileNum;
public FighterPlane(String _name, int _missleNum) {
this.name = _name;
this.missileNum = _missleNum;
}
public void fire() {
if (this.missileNum > 0) {
System.out.println("now fire a missile !");
this.missileNum -= 1;
} else {
System.out.println("No missile left !");
}
}
}
class A {
FighterPlane fp;
public A(FighterPlane fpp) {
this.fp = fpp; //A对象中拥有了FighterPlane对象的引用
}
public void invoke() {
//A对象发送消息给FighterPlane的对象
System.out.println(fp.name);
}
}public class Run {
public Run() {
}
public static void main(String[] var0) {
FighterPlane ftp = new FighterPlane("su35", 10);
//产生A对象,并将ftp作为对象引用传入
A a= new A(ftp);
a.invoke();
}
}
3.谈谈组合与继承的区别以及两者的使用场景(即什么时候宜用组合?什么时候宜用继承? )。
关系:组合是指将已存在的类型作为一个新建类的成员变量类型,两个类之间无上下级关系。
继承是子类继承父类,父类的所有属性和方法都可以被子类访问和调用。JAVA的继承只能是单继承。
使用场景:只需要使用另外一个类的方法时使用组合,需要使用另外一个类的作用时不想被其他的类访问用继承。
4. Java中的运行时多态的含义是什么?有什么作用?请举例说明。
含义:JAVA运行时系统根据调用该方法的实例的类型来决定选择调用哪个方法则被称为运行时多态。具体一点就是子类方法重写了父类方法。使用父类引用指向子类对象,再调用某一父类中的方法时,不同子类会表现出不同结果。
作用:它使得许多事情在运行时就被得以解决,提供了更大的灵活性。
//父类
class A {
void fun()
{
System.out.println(“I am A”);
}
}
//A的子类B
class B extends A
{
void fun()
{
System.out.println(“I am B”);
}
}
//A的子类C
class C extends A
{
void fun()
{
System.out.println(“I am C”);
}
}
class Test
{
public static void main(String[] args)
{
//定义父类对象引用变量
A a;
//子类对象
B b = new B();
C c = new C();
//父类对象引用变量 引用 子类对象
a=b;
a.fun(); //输出 I am B
a=c;
a.fun(); // //输出 I am C
}
}
5.使用接口改写例6.8中的程序。
interface Shape{
abstract public double getArea();
abstract public double getPerimeter();
abstract public void show();
}
class Rect implements Shape{
private int k, m;
public Rect(int width, int height){
this.k = width;
this.m = height;
}
public double getArea(){
return (k * m);
}
public double getPerimeter(){
return (2 * (k + m));
}
public void show(){
System.out.println("Rect Area:" + getArea());
System.out.println("Rect Perimeter:" + getPerimeter());
}
}
class Triangle implements Shape{
private int x, y, z, m;
public Triangle(int _x, int _y, int _z){
this.x = _x;
this.y = _y;
this.z = _z;
this.m = (x + y + z) / 2;
}
public double getArea(){
return(Math.sqrt(m * ( m - x) * ( m - y ) * (m - z)));
}
public double getPerimeter(){
return (2 * m);
}
public void show(){
System.out.println("Rect Area:" + getArea());
System.out.println("Rect Perimeter:" + getPerimeter());
}
}
class Circle implements Shape{
private int r;
public Circle(int _r){
this.r = _r;
}
public double getArea(){
return(r * r *Math.PI);
}
public double getPerimeter(){
return(2 * Math.PI * r);
}
public void show(){
System.out.println("Rect Area:" + getArea());
System.out.println("Rect Perimeter:" + getPerimeter());
}
}
public class RunShape {
public static void main(String args[]){
Rect rect = new Rect(5, 10);
Triangle triangle = new Triangle(3, 4, 5);
Circle circle = new Circle(6);
rect.show();
triangle.show();
circle.show();
}
}
6.自定义一个类,覆写equals方法, 以满足自身业务需求
(1)判断要比较对象的是否为null,若是直接返回false,若不比较则可能会出现空指针异常(NullPointerException);
(2)判断是否在与自身比较(通过==比较地址),若是直接返回true;
(3)判断要比较的两个对象是否为同类,若是再进行接下来比较,若不是直接返回false。若不判断,则可能出现强转异常(classCastException);
(4)通过向下转型,比较两对象内容是否相等。
class Person{
private String name;
private int age;
public Person(String name,int age){
this.name=name;
this.age=age;
}
public String toString(){
return this.name+"今年"+this.age+"岁";
}
public boolean equals(Object obj){//Object类可接受任何类
if(obj==null){//判断是否为空,若不判断则会出先空指针异常(NullPointerException)
return false;
}
if(this==obj){//判断是否在与自身比较(通过比较地址),若是则直接返回true
return true;
}
if(!(obj instanceof Person)){//instanceof作用为判断其左边对象是否为右边对象的实例,此处为判断主方法中equals()方法括号中的对象是否为Person类
return false;
}
//到达此处时必定是同类但不同地址的对象在比较
Person per=(Person)obj;//向下转型,比较属性值
return this.name.equals(per.name)&&this.age==per.age;//判定属性内容是否相等(易错点)
}
}
class Student{}
public class Test{
public static void main(String[] args) {
Person per1=new Person("张三",18);
Person per2=new Person("张三",18);
Person per3=new Person("lisi",19);
Person per4=null;
Student stu=new Student();
System.out.println(per1.equals(per1));//true
System.out.println(per1.equals(stu));//false
System.out.println(per1.equals(per3));//false
System.out.println(per1.equals(per4));//false
}
}
7.举例说明运算符instanceof的使用场景。
该运算符是二目运算符,左边的操作元是一个对象,右边是一个类,当左边的对象是右边的类或子类创建的对象时,该运算符运算的结果是true,否则是false。因此,此运算符可以用于可以确定对象是否属于一个特定的类。
注意:
1.instanceof左边显式声明的类型与右边操作元必须是同种类或存在继承关系,也就是说需要位于同一个继承树,否则会编译错误。
2.左边的对象实例不能是基础数据类型。
3.null用instanceof跟任何类型比较时都是false。
public interface A {
}
public class B implements A{
}
public class C extends B{
}
public class InstanceofTest3 {
public static void main(String[] args) {
A a = null;
B b = null;
boolean result;
result = a instanceof A;
System.out.println(result); // 结果:false null用instanceof跟任何类型比较时都是false
result = b instanceof B;
System.out.println(result); // 结果:false null用instanceof跟任何类型比较时都是false
a = new B();
b = new B();
result = a instanceof A;
System.out.println(result); // 结果:true a是接口A的实例对象引用指向子类类B,类B实现了接口A,所以属于同一个继承树分支
result = a instanceof B;
System.out.println(result); // 结果:true a是接口A的实例对象引用指向子类类B,类B实现了接口A,所以属于同一个继承树分支
result = b instanceof A;
System.out.println(result);// 结果:true b是类B的实例对象,类B实现了接口A,所以属于同一个继承树分支
result = b instanceof B;
System.out.println(result);// 结果:true b是类B的实例对象,类B实现了接口A,所以属于同一个继承树分支
B b2 = new C();
result = b2 instanceof A;
System.out.println(result); // 结果:true b2是父类B引用指向子类C,类B实现了接口A,所以属于同一个继承树分支
result = b2 instanceof B;
System.out.println(result); // 结果:true b2是父类B引用指向子类C,所以属于同一个继承树分支
result = b2 instanceof C;
System.out.println(result); // 结果:true b2是父类B引用指向子类C,所以属于同一个继承树分支
}
}
8.谈谈抽象类与接口的异同以及两者的使用场景。
使用场景:
抽象类:抽象类在被继承时体现的是is-a关系。一般是有继承关系,但父类和子类以及各个子类之间对某些方法的实现又不同。
接口:接口在被实现时体现的是can-do关系。一般是把多个类的相同功能抽象出来,类之间没有继承关系。



