week02_Exercise_01
简答题:
第一题:对象名点调用
1、描述一下对象名点调用成员方法的调用机制
------访问范围
-------调用结果
从上述两个角度来说明这个机制。
答:访问范围看引用对象的数据类型即可。父类访问类型范围只有父类;子类类型访问范围是子类 + 父类
访问结果要看对象的具体类型,尤其是当子类重写了父类的方法,那么调用同名成员方法,结果一定体现子类的行为
第二题:方法重写
2、描述一下方法覆盖/重写的语法,从以下角度:
----访问权限修饰符
—返回值类型(重点测试一下)
答:如果父类方法的返回值类型是一个父类类型,那么子类重写的方法可以返回子类类型
其余任何情况,都需要严格保持一致!
-方法名:必须保持一致
-形参列表:必须保持一致
测试过程中,可以使用注解@Override来检查方法重写的正确性
第三题:final修饰类和方法
3、final修饰类时表示什么?final修饰方法时表示什么?
答:修饰类表示不能被继承,修饰方法表示不能被重写,但仍然可以被继承
第四题:final修饰变量
4、final修饰变量表示什么?分别从两个角度回答:
-修饰基本数据类型和引用数据类型
答:修饰基本数据类型意味着变量的值不能改变了
修饰引用数据类型,修饰的是引用,表示引用不能指向新对象
—修饰局部变量,成员变量,静态成员变量(需要指出如何给它们赋值)
修饰局部变量表示局部常量,除了取值不能改变其余使用和局部变量没有区别。它的赋值必须手动赋值。
修饰成员变量表示成员常量,任然属于对象,存储在对象中,需要创建对象使用。
赋值方式必须是:
显式赋值、构造代码块赋值、构造器赋值 三选一,也只能选择其一
尤其注意使用构造器赋值时,必须让每一个构造器都能够给该成员常量赋值
修饰静态成员变量表示静态成员常量,任然属于类,在类的全局独一份,所以也称之为“全局常量”
赋值方式必须是:
显式赋值、静态代码块赋值
以上二选一,也只能选择其一
第五题:方法重写
5、哪些方法不能发生方法重写?
私有方法、静态方法、构造方法、final修饰的方法
第六题:多态
6、指出多态发生的条件,并说明不能发生多态的场景。
答:必须存在继承,必须存在方法的重写
所以final修饰的类,以及上述写的不能重写的方法,都不能发生多态现象
第七题:父类-子类
7、当存在父类引用指向多个子类对象时:
1:分别访问父子类的同名成员变量,存在多态现象吗?
答:不存在
2:分别调用父子类的同名成员方法,存在多态现象吗?
答:存在
第八题:引用数据类型
8、引用数据类型的强制类型转换(向下转型)语句,能通过编译的条件是什么?
答:只要是把父类引用强转成它的子类类型类型引用,都可以通过编译
第九题:强转的条件
9、引用数据类型的强制类型转换(向下转型)语句,能够运行成功的条件是什么?
答:成功的条件是:向下转型能够成功的前提是,强转后的引用,确实能够真的指向这个对象
具体来说:强转后的引用,要么就是之前父类引用指向的对象的类型(还原)
强转后的引用,要么就是之前父类引用指向对象对象后的父类类型(这里仍然是父类引用指向子类对象)
第十题:instance of的用法
10、. 向下转型如此危险,需要instance of关键字判断后再进行,请描述instance of的使用语法。
答:引用instance of 类名
表示判断引用所指向的对象的对象是否是后面类名的对象或者子类对象
一旦确定是,那就表示左边的引用可以强转成右边类名的引用
第十一题:抽象类
11、请描述抽象类的成员特点(变量、方法、构造器、代码块等)
答:抽象类允许定义普通类中的所有成员,还要多一个抽象方法
编程题:
final语法练习
final修饰成员/静态成员变量,表示一个常量,必须明确地赋值。
package day10;
/**
* 自定义一个类,类中定义三个成员变量a,b,c,用final修饰这三个成员变量
* * 再定义两个静态成员变量staticA和staticB,也用final修饰这两个静态成员变量
* * 然后:
* 1,请用三种不同的方式,分别为a,b,c赋值
* 2,请用两种不同的方式,分别为staticA和staticB赋值
*
* 复习一下成员变量的赋值:
* (掐头去尾)
* 头:默认初始化,有默认值
* 尾:构造器
* 中间:显式赋值和构造代码块,顺序是代码的书写顺序
*
* 最后在加上父子类,先父后子
*/
public class FinalDemo {
final int a = 10;
{
// 局部变量,不是成员变量
int a = 10;
}
static {
// 局部变量,不是静态成员变量
int a = 10;
}
}
class A{
final int a = 10;
final int b;
{
b=20;
}
final int c;
public A(int c){
this.c = c;
}
static final int staticA = 10;
static final int staticB;
static {
staticB = 200;
}
}
练习继承中的构造器使用
使用alt + insert快捷键可以快速生成各种类中结构。子类继承父类后,在子类中按alt + insert快捷键快速创建构造方法时,第一步会让你选择父类构造器(也就是super(参数))
随后才是选择子类自身的成员变量,生成子类构造器。
当然如果选择使用父类无参构造器,这时super()
是隐藏的,即子类对象隐式初始化。
当选择使用子类有参构造器时,这时super(参数)
必须写在子类构造器第一行,这是子类对象的显式初始化。
给出三个层级的继承关系
顶层父类Grandfather,Father继承Grandfather,Son继承Father
成员变量:
Grandfather:gA,a
Father:fA,a
Son:sA,a
成员方法:
Grandfather:testGrand,test
Father:testFather,test
Son:testSon,test
使用快捷键在Son中生成不同的构造方法,调用不同的父类构造器(需要先生成父类相应的构造器)
随后使用多种方式创建Son对象(思考有几种),测试对象名访问成员的机制,理解属性隐藏和方法覆盖
package day10;
/**
* 先定义好相应的类、成员变量、成员方法等
* 然后在子类中,使用alt + insert快捷键自动生成构造方法
* 自己进行练习即可~
* 最后创建对象,使用对象名点访问成员,查看结果即可
*/
public class SubClazzConstructorDemo {
public static void main(String[] args) {
Son s = new Son();
System.out.println(s.a);// 3
Father f = new Son();
System.out.println(((Son) f).a);// 2
Grandfather gf = new Son();
System.out.println(((Son) gf).a);// 1
System.out.println("======第二组结果======");
s.test();
f.test();
gf.test();
System.out.println("======第三组结果=======");
((Son) f).testSon();
((Son) gf).testFather();
}
}
class Grandfather {
int gA = 1;
int a = 1;
public void testGrand() {
System.out.println("Grand独有");
}
public void test() {
System.out.println("testGrand");
}
public Grandfather(int gA, int a) {
this.gA = gA;
this.a = a;
}
public Grandfather() {
}
}
class Father extends Grandfather {
int fA = 2;
int a = 2;
public void testFather() {
System.out.println("Father独有");
}
public void test() {
System.out.println("testFather");
}
public Father(int fA, int a) {
this.fA = fA;
this.a = a;
}
public Father() {
}
public Father(int gA, int a, int fA, int a1) {
super(gA, a);
this.fA = fA;
this.a = a1;
}
}
class Son extends Father {
int sA = 3;
int a = 3;
public void testSon() {
System.out.println("Son独有");
}
public void test() {
System.out.println("testSon");
}
public Son() {
}
public Son(int gA, int a, int fA, int a1, int sA, int a2) {
super(gA, a, fA, a1);
this.sA = sA;
this.a = a2;
}
public Son(int sA, int a) {
this.sA = sA;
this.a = a;
}
public Son(int gA, int a, int fA, int a1) {
super(gA, a, fA, a1);
}
}
运行及结果:
多态语法基础练习
牢记多态发生的条件
请根据题目,作出合理设计,定义如下类:
父类Person
属性:String name,int age
行为:eat();
子类SouthPerson
属性:String name,int age,double salary
行为:eat(),swim()
子类NorthPerson
属性:String name,int age,double height
行为:eat(),drink()
写代码实现,eat()方法的多态效果
1,人都要吃饭
2,南方人喜欢吃米饭
3,北方人喜欢吃面食
最后,在测试类中,编写测试代码,要求进行如下测试:
1,编写测试方法,
要求该方法允许传入SouthPerson对象和NorthPerson对象,并在方法体中调用它们的eat()方法
方法调用的结果一致吗?
2,用父类引用指向子类对象的方式创建SouthPerson对象,能否直接访问salary属性和swim()方法?
如果不能,应该怎么写代码让它能够正常调用?
3,用父类引用指向子类对象的方式创建NorthPerson对象,能否(直接或写代码)访问salary属性和swim()方法?
如果不能,将该对象引用强转为SouthPerson引用,能否成功?为什么?
package day10;
/**
* 回答以下问题:
* 1,编写测试方法,
* 要求该方法允许传入SouthPerson对象和NorthPerson对象,并在方法体中调用它们的eat()方法,方法调用的结果一致吗?
* 显然方法调用的结果是不一致的,方法调用结果要根据对象的具体类型而定。
* 而SouthPerson和NorthPerson这两个类,都重写了继承的eat()方法。
* <p>
* 2,用父类引用指向子类对象的方式创建SouthPerson对象,能否直接访问salary属性和swim()方法?
* 如果不能,应该怎么写代码让它能够正常调用?
* 显然是不能直接访问的,引用限制了访问范围。
* 如果想要正常访问,需要进行强制类型转换。
* <p>
* 3,用父类引用指向子类对象的方式创建NorthPerson对象,能否(直接或写代码)访问salary属性和swim()方法?
* 如果不能,将该对象引用强转为SouthPerson引用,能否成功?为什么?
* 不能,不在同一条继承链中的两个类没有任何关系。也不可能发生强转。
*/
public class PolymorphicDemo {
public static void main(String[] args) {
NorthPerson np = new NorthPerson();
SouthPerson sp = new SouthPerson();
test(np);
test(sp);
Person p = new NorthPerson();
}
private static void test(Person p) {
p.eat();
}
}
abstract class Person {
String name;
int age;
public abstract void eat();
}
class SouthPerson extends Person {
double salary;
@Override
public void eat() {
System.out.println("南方人吃米饭");
}
public void swim() {
System.out.println("南方人会游泳");
}
}
class NorthPerson extends Person {
double height;
@Override
public void eat() {
System.out.println("北方人吃馒头");
}
public void drink() {
System.out.println("北方人特别能喝酒");
}
}
运行结果图:
抽象类基础语法练习
完成抽象类的基础语法练习,按照说明操作即可。
定义抽象类A,抽象类B继承A,普通类C继承B。
A类中,定义成员变量a赋值为10,抽象showA方法
B类中,定义成员变量b赋值为20,抽象showB方法
C类中,定义成员变量c赋值为30,重写showA方法打印a,重写showB方法打印b,定义showC方法,打印c
然后在测试类中,创建C类的对象,调用showA方法,showB方法,showC方法。
然后查看方法调用结果,思考为什么会出现这种现象。
package day10;
/**
* 定义抽象类A,抽象类B继承A,普通类C继承B
* A类中,定义成员变量a赋值为10,抽象showA方法。
* B类中,定义成员变量b赋值为20,抽象showB方法。
* C类中,定义成员变量c赋值为30,重写showA方法打印a,重写showB方法打印b,定义showC方法,打印c。
* 测试类中,创建C对象,调用showA方法,showB方法,showC方法。
*/
public class AbstractClazzDemo {
public static void main(String[] args) {
C c = new C();
c.showA();
c.showB();
c.showC();
}
}
abstract class A {
int a = 10;
public void showA(){
System.out.println("showA");
}
}
abstract class B extends A {
int b = 20;
public abstract void showB();
}
class C extends B {
int c = 30;
@Override
public void showA() {
System.out.println(a);
}
@Override
public void showB() {
System.out.println(b);
}
public void showC() {
System.out.println(c);
}
}
运行结果图:
ract class A {
int a = 10;
public void showA(){
System.out.println("showA");
}
}
abstract class B extends A {
int b = 20;
public abstract void showB();
}
class C extends B {
int c = 30;
@Override
public void showA() {
System.out.println(a);
}
@Override
public void showB() {
System.out.println(b);
}
public void showC() {
System.out.println(c);
}
}
运行结果图:
![在这里插入图片描述](https://img-blog.csdnimg.cn/47ee03d8e3364838bfa22f8e53a54cff.png#pic_center)