目录
4.protected访问修饰符、final关键字以及方法的重写
前言
我的JavaSE语法专栏地址👇,可以看看哦,可能你会有不一样的收获。JavaSE_会飞的阿喵的博客-CSDN博客https://blog.csdn.net/che__dan/category_11970438.html?spm=1001.2014.3001.5482
继承和多态可以说是Java这种面向对象语言的精髓了,本篇会详细的介绍继承,让你对继承有进一步的认识,多态就留在下一篇来介绍咯。
✏️继承
1.继承的引入
Java是面向对象语言,Java中使用类来对现实世界的实体来进行描述,类经过实例化之后的对象来表示现实中的实体,但是事物之间可能会有一些联系。
现在我们用Java对 狗与猫 进行描述。有以下代码:
public class Cat {
String name;
String color;
int age;
public void eat(){
System.out.println("俺在吃饭!!!");
}
public void mew() {
System.out.println("喵喵喵~");
}
}
----------------------------------Dog.java-----------------------------------------------
public class Dog {
String name;
String color;
int age;
public void eat(){
System.out.println("俺在吃饭!!!");
}
public void Bark() {
System.out.println("旺旺旺~");
}
}
容易发现,上面的代码有点累赘,重复的太多了,只有 “叫声” 的方法不一样。那能否将这些共性抽取呢?面向对象思想中提出了继承的概念,专门用来进行共性抽取,实现代码复用。
2. 继承的概念及语法
继承:是面向对象程序设计使代码可以复用的最重要的手段,它允许程序员在保持原有类特 性的基础上进行扩展,增加新功能,这样产生新的类,称派生类。继承呈现了面向对象程序设计的层次结构, 体现了由简单到复杂的认知过程。继承主要解决的问题是:共性的抽取,实现代码复用。
语法:表示继承的关系要用到extends关键字。
修饰符 class 子类 extends 父类 {
// ...
}
那么上面的“狗”与“猫”类可以继承“动物”这个类:
上述图示中,Dog和Cat都继承了Animal类,其中:Animal类称为父类/基类或超类,Dog和Cat可以称为Animal的子类/派生类,继承之后,子类可以复用父类中成员,子类在实现时只需关心自己新增加的成员即可。
看代码:
public class Animal {
String name;
String Color;
int age;
public void eat(){
System.out.println("俺在吃饭!!!");
}
}
--------------------------------Cat.java-------------------------------------------------
public class Cat extends Animal{
public void mew() {
System.out.println("喵喵喵~");
}
}
--------------------------------Dog.java-------------------------------------------------
public class Dog extends Animal{
public void Bark() {
System.out.println("旺旺旺~");
}
}
子类会将父类中的成员变量或者成员方法继承到子类中,这时Cat与Dog类可以访问Animal类的成员。
public class Main {
public static void main(String[] args) {
Dog dog = new Dog();
dog.name = "小白";
dog.color = "白色";
dog.age = 2;
System.out.println(dog.name);
System.out.println(dog.color);
System.out.println(dog.age + "岁");
dog.eat();
dog.Bark();
}
}
结果:
小白
白色
2岁
俺在吃饭!!!
旺旺旺~
3.访问父类成员
3.1 子类中访问父类的成员变量
-
当子类和父类 不存在 同名成员变量
public class Father {
int a;
int b;
int c;
}
------------------------------------Son.java-----------------------------------------------
public class Son extends Father {
int d;
public void Test(){
a = 40; //访问从父类中继承下来的 a
b = 50; //访问从父类中继承下来的 b
c = 60; //访问从父类中继承下来的 c
d = 70; //访问子类自己的d
}
}
--
- 子类和父类成员变量同名
public class Father {
int a = 12;
String b = "我是父类的b";
int c;
}
---------------------------------------Son.java------------------------------------------
public class Son extends Father {
char a; //与父类中成员 b 同名,但 类型不同.
String b; //与父类中成员 c 同名,且类型相同.
public void print(){
a = 'a'; // 访问父类继承的a,还是子类自己新增的a?
b = "我是子类的b"; // 访问父类继承的b,还是子类自己新增的b?
c = 200; // 子类没有c,访问的肯定是从父类继承下来的c
System.out.println("a:" + a);
System.out.println("b:" + b);
System.out.println("c:" + c);
}
}
---------------------------------------Main.java-----------------------------------------
public class Main {
public static void main(String[] args) {
Son son = new Son();
son.print();
}
}
结果:
a:a
b:我是子类的b
c:200
可以看到:
(1)如果访问的成员变量子类中有,优先访问自己的成员变量。
(2)如果访问的成员变量子类中无,则访问父类继承下来的,如果父类也没有定义,则编译报错。
(3)如果访问的成员变量与父类中成员变量同名(尽管是类型不同),则优先访问自己的。
其实就是 就近原则,自己有优先自己的,如果没有则向父类中找。
3.2 子类中访问父类的成员方法
- 成员方法名字不同
public class Father {
public void A () {
System.out.println("Father类中的A方法!!!");
}
}
--------------------------------Son.java-------------------------------------------------
public class Son extends Father {
public void B(){
System.out.println("Son类中的B方法!!!");
}
public void C(){
System.out.println("Son类中的C方法!!!");
}
public void test() {
A(); //访问父类中的A()方法
B(); //访问子类中的B()方法
C(); //访问子类中的C()方法
}
}
--------------------------------Main.java------------------------------------------------
public class Main {
public static void main(String[] args) {
Son son = new Son();
son.test();
}
}
结果:
Father类中的A方法!!!
Son类中的B方法!!!
Son类中的C方法!!!
总结:
成员方法没有同名时,在子类方法中或者通过子类对象访问方法时,则优先访问自己的,自己没有时再到父类中找,如果父类中也没有则报错。
--
- 成员方法名字相同
public class Father {
public void A () {
System.out.println("Father类中的A方法!!!");
}
public void B(){
System.out.println("Father类中的B方法!!!");
}
}
----------------------------------Son.java-----------------------------------------------
public class Son extends Father {
public void A(int x){
System.out.println("Son类的 A(int x)方法!!!");
}
public void C(){
System.out.println("Son类中的C方法!!!");
}
public void test() {
A(); //没有传参数,访问的时父类的A方法
A(4); //传了参数,访问的是子类的A方法
B(); //子类没有,访问的是父类的方法
C(); //永远访问到的都是子类中的C(),因为父类没有
}
}
--------------------------------------Main.java------------------------------------------
public class Main {
public static void main(String[] args) {
Son son = new Son();
son.test();
}
}
结果:
Father类中的A方法!!!
Son类的 A(int x)方法!!!
Father类中的B方法!!!
Son类中的C方法!!!
总结:
- 通过 子类的对象(实例) 访问 父类与子类中 不同名方法时,优先在子类中找,找到则访问,否则在父类中找,找到则访问,如果都没有找到就报错。
- 通过 子类的对象(实例) 访问 父类与子类 同名方法时,如果父类和子类同名方法的参数列表 不同(也就是重载),根据调用方法适传递的参数选择合适的方法访问,如果没有找到则报错。(这就是跟方法重载一样的)
- 这里用到了方法重载,子类可以重载父类的方法。 (其实还有方法重写,重写就是方法名、参数列表相同,并且不能修改,这两者本质是不同的)。
4.protected访问修饰符、final关键字以及方法的重写
4.1 protected访问修饰符
(在这篇文章👇中介绍了其它的访问修饰符)
父类中不同访问权限的成员,在子类中的可见性又是什么样子的呢?
案例:
demo1包:
public class FatherDemo1 {
public int a;
int b;
private int c;
protected int d;
}
-------------------------------SonDemo1,java---------------------------------------------
public class SonDemo1 extends FatherDemo1 {
public void test () {
a = 1; //父类中public成员在相同包子类中可以直接访问
b = 2; //父类中默认访问权限修饰的成员在相同包子类中可以直接访问
c = 3; //编译报错,父类private成员在相同包子类中不可见
d = 4; //父类中protected成员在相同包子类中可以直接访问
System.out.println("a:" + a + " b:" + b + " c:" + c + " d:" + d);
}
}
-------------------------------Main.java------------------------------------------------
public class Main {
public static void main(String[] args) {
SonDemo1 son = new SonDemo1();
son.test();
}
}
结果:
结果显而易见,在同一个包中就 private 不能被访问。
--
demo2包:
import demo1.FatherDemo1;//导包
public class SonDemo2 extends FatherDemo1 {
public void test () {
a = 1; //父类中public成员在 不同包子类中 可以直接访问
b = 2; //编译报错,父类中默认访问权限修饰的成员在 不同包子类中 不可以直接访问
c = 3; //编译报错,父类private成员在 不同包子类中 不可见
d = 4; //父类中protected成员在 不同包子类中 可以直接访问
}
}
---------------------------------Main.java-------------------------------------------------
public class Main {
public static void main(String[] args) {
SonDemo2 son = new SonDemo2();
son.test();
}
}
结果:
在不同包中的子类 (父类在另一个包中),protectde修饰符能被访问,而默认修饰符与private都不能被访问。
--
demo3包:
import demo1.FatherDemo1;
public class SonDemo3 {
public void test () {
FatherDemo1 fatherDemo1 = new FatherDemo1();
fatherDemo1.a = 1; //父类中public成员在 不同包的非子类中 可以直接访问
fatherDemo1.d = 4; //编译报错,父类中protected成员在 不同包的非子类中 不能直接访问
fatherDemo1.b = 2; //编译报错,父类中默认访问权限修饰的成员在 不同包的非子类中 不可以直接访问
fatherDemo1.c = 3; //编译报错,父类private成员在 不同包的非子类中 不可见
System.out.println("a:" + fatherDemo1.a + " b:" + fatherDemo1.b + " c:" + fatherDemo1.c + " d:" + fatherDemo1.d);
}
}
-------------------------------------Main.java---------------------------------------------
public class Main {
public static void main(String[] args) {
SonDemo3 son = new SonDemo3();
son.test();
}
}
结果:
这里与上一个案例的区别是SonDemo3没有继承父类了,当一个包中的类引用了另一个包中的类,protectde修饰符是不能被访问的(前提是该类不是引用类的子类)。
如果是在同一个包中引用(两个类在一个包),就算是没有继承,protectde修饰符也能被访问!
4.2 final关键字
final 跟C语言中的 const 相似,修饰一个变量的时候,这个变量就变成了常量,也就是不能再修改了。
final可以修饰:成员变量(方法内的局部变量也行)、类、方法
--
- 修饰变量,表示常量:
public static void main(String[] args) {
final int a = 10;
a = 11;
System.out.println(a);
}
结果:
- -
- 修饰类(则该类不能被继承):
final public class Father {
}
----------------------------------Son.java------------------------------------------------
public class Son extends Father{
}
----------------------------------Main.java------------------------------------------------
public class Main {
public static void main(String[] args) {
Son son = new Son();
}
}
结果:
- -
- 修饰方法,表示该方法不能被重写👇。
4.3 方法重写
重写是 子类 对 父类的非静态、非private修饰、非final修饰的方法进行重新编写, 返回值和形参都不能改变。即外壳不变,核心重写。
--
- 子类在重写父类的方法时,方法名、形参(顺序、类型)、返回值类型 要保持一致。
public class Animal {
String name;
int age;
//……
public void eat () {
System.out.println("在吃饭!!!");
}
}
----------------------------------Cat.java-----------------------------------------------
public class Cat extends Animal{
//重写父类的eat方法
public void eat () {
System.out.println("在吃鱼!!!");
}
}
----------------------------------Dog.java-----------------------------------------------
public class Dog extends Animal {
//重写父类的eat方法
public void eat () {
System.out.println("在吃骨头!!!");
}
}
----------------------------------Main.java----------------------------------------------
public class Main {
public static void main(String[] args) {
Animal animal = new Animal();
Dog dog = new Dog();
Cat cat = new Cat();
animal.eat();
dog.eat();
cat.eat();
}
}
结果:
在吃饭!!!
在吃骨头!!!
在吃鱼!!!
重写的好处在于子类可以根据需要,定义特定于自己的行为。这里案例:狗吃饭是吃骨头,猫是吃🐟。我们需要根据子类的具体情况来重写方法。
--
- 被重写的方法返回值类型可以不同,但是必须是具有父子关系的,就是返回值是 类 类型,两个类为继承和被继承关系。
public class Animal {
String name;
int age;
public Animal WhatAnimal(){
return this;
}
}
----------------------------------Cat.java-----------------------------------------------
public class Cat extends Animal{
public Cat WhatAnimal(){
return this;
}
}
----------------------------------Dog.java-----------------------------------------------
public class Dog extends Animal {
public Dog WhatAnimal(){
return this;
}
}
----------------------------------Main.java----------------------------------------------
public class Main {
public static void main(String[] args) {
Animal animal = new Animal();
Dog dog = new Dog();
Cat cat = new Cat();
//返回 那个类的 包名 + 类名
System.out.println(dog.WhatAnimal().getClass().getName());
System.out.println(cat.WhatAnimal().getClass().getName());
}
}
结果:
demo9.Dog
demo9.Cat
(上面用到了反射的知识,不用理会,后面会介绍,这里就当看一个乐子)这里就简单的举了个例子,子类重写方法的返回值都是Animal的子类类型,即返回值类型不同,但是程序能通过。
--
- 访问权限不能比父类中被重写的方法的访问权限更低。
例如:如果父类方法被public修饰,则子类中重写该方法就不能声明为 protected。
public class Father {
public void test () {
System.out.println("Father类的text()!!!");
}
}
-------------------------------Sno.java-------------------------------------------------
public class Son extends Father{
protected void test(){
System.out.println("Son类的text()!!!");
}
}
-------------------------------Main.java-----------------------------------------------
public class Main {
public static void main(String[] args) {
Son son = new Son();
son.test();
}
}
结果:
--
- 父类中被static、private、final修饰的方法不能被重写。
private这里就不举例了,private修饰的方法,外面根本访问不到,private本身就是描述“私有的”不可能让子类“看到”,就无法重写。如果子类写了一个一摸一样的方法,就不叫重写了,就是重新定义一个方法罢了。
--
- 重写与重载的区别
5.super关键字
上文演示了很多示例,知道了 子类与父类成员同名的时候最先调用的是子类的成员,那有没有方法可以访问同名成员中的父类那一个呢?
如果要在子类方法中访问父类同名成员时,直接访问是无法做到的,Java提供了super关键字,该关键字主要作用:在子类方法中访问父类的成员。
public class Father {
int a;
int b;
public void A () {
System.out.println("Father类中的A方法!!!");
}
public void B(){
System.out.println("Father类中的B方法!!!");
}
}
----------------------------------Son.java-----------------------------------------------
public class Son extends Father {
int a; // 与父类中成员变量同名且类型相同
String b;// 与父类中成员变量同名但类型不同
// 与父类中A()构成重载
public void A(int x){
System.out.println("Son类的 A(int x)方法!!!");
}
// 与父类中B()构成重写
public void B(){
System.out.println("Son类中的B方法!!!");
}
public void test(){
// 访问父类的成员变量时,需要借助super关键字
super.a = 200;
System.out.println(super.a);
super.b = 200;
System.out.println(super.b);
// 对于同名的成员变量,直接访问时,访问的都是子类的
a = 100;
System.out.println(a);
b = "我是子类的b";
System.out.println(b);
// 父类和子类中构成重载的方法,直接可以通过参数列表区分清访问父类还是子类方法
A(); // 没有传参,访问父类中的A()
A(40);// 传递int参数,访问子类中的A(int)
// 如果在子类中要访问重写的基类方法,则需要借助super关键字
B();
super.B();
}
}
----------------------------------Main.java----------------------------------------------
public class Main {
public static void main(String[] args) {
Son son = new Son();
son.test();
}
}
结果:
200
200
100
我是子类的b
Father类中的A方法!!!
Son类的 A(int x)方法!!!
Son类中的B方法!!!
Father类中的B方法!!!
总结:super是获取到子类对象中从父类继承下来的部分。
--
重要:super关键字只能在非静态方法中使用。
public class Father {
int a;
int b;
}
----------------------------------Son.java------------------------------------------------
public class Son extends Father {
int a; // 与父类中成员变量同名且类型相同
String b;// 与父类中成员变量同名但类型不同
public static void test2(){
super.a = 100; //报错
}
}
5.1 super在内存中的体现
案例:
public class Father {
int a;
int b;
public void A () {
System.out.println("Father类中的A方法!!!");
}
public void B(){
System.out.println("Father类中的B方法!!!");
}
}
----------------------------------Son.java-----------------------------------------------
public class Son extends Father {
int a; // 与父类中成员变量同名且类型相同
String b;// 与父类中成员变量同名但类型不
// 与父类中A()构成重载
public void A(int x){
System.out.println("Son类的 A(int x)方法!!!");
}
// 与父类中B()构成重写
public void B(){
System.out.println("Son类中的B方法!!!");
}
}
----------------------------------Main.java----------------------------------------------
public class Main {
public static void main(String[] args) {
Son son = new Son();
}
}
super代表的是子类的父类型特征,不是父类的引用。Object类是所有类的父类,只不过被隐藏了,这里可以不考虑。(Object类具体的在下一篇介绍)
Son它是Father的子类,先初始化Father类型的特征(最先初始化的是Object的特征),再初始化Son自己的特征,Son的super代表这Father的特征。
5.2 super与this的异同点
相同:
- 只能在类的非静态方法中使用,用来访问非静态成员方法和字段。
- 在构造方法中调用时,必须是构造方法中的第一条语句,并且不能同时存在。
不同:
- this是 当前对象的引用,super相当于是子类对象中从 父类继承下来部分成员的引用。
- 在非静态成员方法中,this用来访问本类的方法和属性,super用来访问父类继承下来的方法和属性。
- 在构造方法中:this()用于调用本类构造方法,super()用于调用父类构造方法,两种调用不能同时在构造方法中出现。
- 构造方法中一定会存在super()的调用,没有写编译器也会增加,但是this()用户不写则没有。
6.子类构造方法
JavaSE语法(6)——【类和对象(类的内存模型、访问限定符public、private等、包的导入……)】_会飞的阿喵的博客-CSDN博客https://blog.csdn.net/Che__dan/article/details/127669373?spm=1001.2014.3001.5502 在上面👆的文章中我介绍过 this在构造方法中的应用,就是 this() 表示本类的构造方法;同理,在这里 super() 表示父类的构造方法。
new一个子类对象时,需要先调用父类的构造方法,然后执行子类的构造方法。
public class Father {
public Father() {
System.out.println("Father类的构造方法!!!");
}
}
----------------------------------Son.java------------------------------------------------
public class Son extends Father {
public Son(){
super();//父类的构造方法
System.out.println("Son类的构造方法!!!");
}
}
----------------------------------Main.java------------------------------------------------
public class Main {
public static void main(String[] args) {
Son son = new Son();
}
}
结果:
Father的构造方法!!!
Son类的构造方法!!!
--
- 没有写super()时,编译器会自动添加,而且super()必须是子类构造方法中第一条语句,并且只能出现一次。
public class Father {
public Father() {
System.out.println("Father类的构造方法!!!");
}
}
----------------------------------Son.java------------------------------------------------
public class Son extends Father {
public Son(){
System.out.println("Son类的构造方法!!!");
}
}
----------------------------------Main.java------------------------------------------------
public class Main {
public static void main(String[] args) {
Son son = new Son();
}
}
结果:
Father的构造方法!!!
Son类的构造方法!!!
--
- 若父类显式定义无参 或者 为默认的构造方法,则在 子类构造方法 第一行默认有隐含的super()调用,即调用父类(基类)构造方法。
--
- 如果父类构造方法是带有参数的,此时需要为子类显式定义构造方法,并在子类构造方法中选择合适的父类构造方法调用,否则编译失败。
public class Father {
String f_name;
int f_age;
public Father(String f_name,int f_age) {
this.f_name = f_name;
this.f_age = f_age;
System.out.println("Father类的构造方法!!!");
}
}
----------------------------------Son.java-----------------------------------------------
public class Son extends Father {
String s_name;
int s_age;
public Son(String f_name,int f_age,String s_name,int s_age){
super(f_name,f_age);
this.s_name = s_name;
this.s_age = s_age;
System.out.println("Son类的构造方法!!!");
}
public void print(){
System.out.println("f_name:" + f_name +" f_age:" + f_age + " s_name:" + s_name + " s_age:" + s_age);
}
}
----------------------------------Main.java----------------------------------------------
public class Main {
public static void main(String[] args) {
Son son = new Son("张三",40,"张小",19);
son.print();
}
}
结果:
Father类的构造方法!!!
Son类的构造方法!!!
f_name:张三 f_age:40 s_name:张小 s_age:19
--
- super()只能在子类构造方法中出现一次,并且不能和this同时出现
7.代码块在继承中的执行顺序
JavaSE语法(7)——【static关键字、代码块】_会飞的阿喵的博客-CSDN博客https://blog.csdn.net/Che__dan/article/details/127875995?spm=1001.2014.3001.5502 在上一篇文章中👆介绍了代码块在一个类中的执行顺序,这里介绍一下在继承中它们是如何执行的。
public class Father {
String name;
int age;
//……
public Father() {
System.out.println("父类的构造方法!!!");
}
{
System.out.println("父类的实例代码块!!!");
}
static {
System.out.println("父类的静态代码块!!!");
}
}
------------------------------Son.java---------------------------------------------------
public class Son extends Father{
public Son(){
System.out.println("子类的构造方法!!!");
}
{
System.out.println("子类的实例代码块!!!");
}
static{
System.out.println("子类的静态代码块!!!");
}
}
-------------------------------Main.java-------------------------------------------------
public class Main {
public static void main(String[] args) {
Son son = new Son();
System.out.println("============================================================");
Son son1 = new Son();
}
}
结果:
父类的静态代码块!!!
子类的静态代码块!!!
父类的实例代码块!!!
父类的构造方法!!!
子类的实例代码块!!!
子类的构造方法!!!
============================================================
父类的实例代码块!!!
父类的构造方法!!!
子类的实例代码块!!!
子类的构造方法!!!
总结:
(1)父类静态代码块 优先于 子类静态代码块执行,且是最早执行。
(2)第二次实例化子类对象时,父类和子类的静态代码块都将不会再执行。
(3)剩下的就是 父类 ->子类 实例->构造
8.继承方式
- 单继承
例子就不举了,上面的全是。
--
- 多层继承
public class Father {
}
-------------------------------------------------------------------------------------------
public class A extends Father{
}
-------------------------------------------------------------------------------------------
public class B extends A{
}
--
- 不同的类继承同一个类
public class Father {
}
-------------------------------------------------------------------------------------------
public class A extends Father{
}
-------------------------------------------------------------------------------------------
public class B extends Father{
}
--
- Java中不能多继承!
public class Father {
}
-------------------------------------------------------------------------------------------
public class Father2 {
}
-------------------------------------------------------------------------------------------
public class Son extends Father,Father2{
}
这里它会报错。
✏️组合
继承、组合都是一种 表达类之间关系 的方式。组合没有关键字,不像继承那样 有extends。组合的特征就是 将 某一个类的实例作为另一个类的成员变量。
继承表示对象之间是is-a的关系,比如:狗是动物,猫是动物。
组合表示对象之间是has-a的关系,比如:汽车有轮子、有发动机、有椅子……。
public class Engine {
}
---------------------------------------------------------
public class Wheel {
}
---------------------------------------------------------
public class Car {
//它的轮子
Wheel wheel;
//它的发动机
Engine engine;
//……
}
上面这样的形式就是组合。
--
案例:计算圆锥的体积
圆锥的底是一个圆,在计算体积时,首先得计算圆的面积,我们这里创建两个对象。
(1)Circle类 (圆对象)
(2)Cone类 (圆锥对象)
圆锥对象在计算体积时,先委托圆锥的底 bottom(圆对象的一个实例) 调用自己的方法getArea()来计算自己的面积,然后圆锥对象再根据bottom计算出的结果来计算自己的体积。
--
- Circle类 (圆对象)
public class Circle {
//半径
public double radius;
//面积
public double area;
//构造方法
public Circle() {}
public Circle(double r) {
this.radius = r;
}
//设置半径
public void setRadius(double r){
this.radius = r;
}
//获取半径
public double getRadius(){
return radius;
}
//计算面积
public double getArea(){
area = 3.14 * radius * radius;
return area;
}
}
--
- Cone类 (圆锥对象)
public class Cone {
//自己的底,底是一个圆
public Circle bottom;
//高
public double height;
//构造方法
public Cone() {}
public Cone(double h,Circle c){
this.height = h;
this.bottom = c;
}
//设置高
public void setHeight(double h){
this.height = h;
}
//设置底的半径
public void setBottomRadius(double r) {
bottom.setRadius(r);
}
//计算自己的体积
public double getVolume() {
//避免底没有传进来
if(bottom == null){
return -1;
} else {
//开始计算
return bottom.getArea() * height / 3.0;
}
}
}
--
- Main
public class Main {
public static void main(String[] args) {
//创建一个圆锥
Circle circle = new Circle(4);
double h = 12;
Cone cone = new Cone(h,circle);
double V = cone.getVolume();
System.out.println("底面半径为4,高为12的圆锥的体积:" + V);
//修改底与高,半径改为24,高改为6,再计算体积
cone.setBottomRadius(24);
cone.setHeight(6);
V = cone.getVolume();
System.out.println("底面半径为24,高为6的圆锥的体积:" + V);
}
}
这里只是简单地写了一些功能,便于理解,你可以自己拓展一下。
这里就用到了组合,圆锥它有一个底(为圆),它们的关系为have-a的关系。圆锥类委托了圆类,叫圆类求自己的面积,圆锥类只管调用,并不会去管圆类是如何实现的。
完
ps:本篇文章的知识点有一小点的多,写到这儿,加上代码总共有17884个字,嗯嗯嗯……不如关注+收藏一下,以免找不到我了哦!