Educoder java面向对象设计
任务描述
相关知识
面向对象思想
封装
继承
构造函数
super()和this()
编程要求
测试说明
任务描述
本关任务:按要求编写一个Java应用程序,巩固Java面向对象知识。
相关知识
为了完成本关任务,我们回顾一下前面所学知识:1.面向对象思想 ;2.封装;3.继承;4.构造函数;5.super()和this()。
面向对象思想
构造器:new就是一个构造器,作用是:①分配空间;②赋初始值(避免错误,简化输入);
new Object(Parameters)构造器调用构造函数,传参为了赋初始值;
对象的基本元素是:属性和方法 类成员(属性和方法)。属性最为重要,属性的集合是一个状态,方法是一个状态到另一个状态的桥梁;
封装:属性和处理属性的方法集合起来。把数据及数据的操作方法放在一起,作为一个相互依存的整体,即对象。
面向对象是基于面向过程而言的,面向对象是将功能等通过对象来实现,将功能封装进对象之中,让对象去实现具体的细节;这种思想是将数据作为第一位,而方法或者说是算法作为其次,这是对数据一种优化,操作起来更加的方便,简化了过程。
封装
访问权限的控制常被称为是具体实现的隐藏。把数据和方法包装进类中,以及具体实现的隐藏共同被称为封装。
public:可以被所有其他类访问;
protected:自身、子类、及同一个包中类(接受包外的子类访问);
default:同一包中的类可以访问,声明时没有加修饰符,认为是friendly(拒绝一切外包访问);
private:只能被自己访问和修改。
类的访问控制符只有三种:public、private、protected
default是无访问控制符。
继承
在一个子类被创建的时候,首先会在内存中创建一个父类对象,然后在父类对象外部放上子类独有的属性,两者合起来形成一个子类的对象。继承使子类拥有父类所有的属性和方法,但是父类对象中的私有属性和方法,子类是无法访问到的,只是拥有,但不能使用。子类不能继承父类的构造函数,只是显式或隐式调用,可以从子类调用超类的构造函数。
用new创建子类的对象时,若子类没有带参构造函数,将先执行父类的无参构造函数,然后再执行自己的构造函数。父类定义了有参的构造函数后,可以不定义无参的构造函数,系统也不会提供默认的无参构造函数。这时子类只能调用父类的有参构造函数。
Java类是单继承,Java接口可以多继承。类可以实现多个接口,接口可以继承(扩展)多个接口。先继承后实现接口。
组合和继承
组合是指在新类里面创建原有的类的对象,重复利用已有类的功能。(“has - a”)
组合和继承都允许在新的类中设置子对象,只是组合是显式的,而继承是隐式的。组合中的整体类和继承中的子类对应,组合中的局部类和继承中的父类对应。
组合和继承的选择规则:
① 除非两个类之间是“is - a”的关系,否则不要轻易地使用继承。过多的使用继承会破坏代码的可维护性,当父类修改时,会影响所有继承他的子类,增加了程序维护的难度和成本。
②不要仅仅为实现多态而使用继承,如果类之间没有“is - a”关系,可以通过实现接口与组合的方式来达到相同的目的。
构造函数
用来在对象实例化时初始化对象的成员变量。
特点:
① 方法名必须和类名相同,不能有返回值(也不能为void);
② 一个类可以有多个构造函数,没有定义的话,编译器会在源代码编译成字节码文件的过程中会提供一个没有参数的默认的构造方法。若定义后,不会再创建默认的构造方法;
③构造函数的参数有(0到多个);
④构造函数在对象实例化时会被自动调用,且只运行一次;普通方法是在程序执行到时才调用且可以被该对象调用多次;
⑤构造函数的作用是完成对象的初始化;
⑥构造函数不能被继承,不能被覆盖,能被重载;
⑦子类可以通过super()关键字来显示调用父类的构造函数,父类没有提供无参构造,子类的构造函数中必须显式得调用父类的构造函数;
⑧父类和子类都没有定义构造函数时,编译器都会为父类生成一个默认的无参构造,给子类也生成一个默认的无参的构造函数;
⑨构造方法会在成员变量之后初始化;
⑩构造方法不能被static、final、synchronize、abstract、native修饰,但可以被public、private、protect修饰。
在继承的时候,父类当然也有构造方法,如果你要创建子类的对象,那么执行的过程首先是调用父类的无参构造方法生成父类的对象,然后再调用子类的无参构造方法来生成子类对象。继承的时候都是先生成父类的对象,然后再生成子类的对象。
通过使用this关键字带上参数,可以在一个构造函数中调用另外一个构造函数。这是this除了单纯表示“当前对象”(注意是针对对象而不是类的概念)之外的第二个作用。但是注意3点:
① 必须放在第一行;
②只能调用一个其它的构造函数。(也许可以这样理解,正是因为有了第一点,如果可以调用多个的话,那么就无法放在“第一行”,所以只能允许一次调用);
③只能是构造函数调用构造函数,普通函数无法调用构造函数。
super()和this()
super()关键字表示超类的意思,当前类是从超类继承而来。
this表示当前对象;
只有在重写(Override)父类的方法中,子类要调用继承自父类的方法,才使用super关键字。
使用super()或者this()方法是必须放在构造函数的第一行;
由于this函数指向的构造函数默认有super()方法,所以规定this()和super()不能同时出现在一个构造函数中。
因为static方法或者语句块没有实例时可以使用,而此时不需要构造实例,所以不能用this()和super()。
编程要求
根据提示,在右侧编辑器Begin-End处补充代码:
声明一个抽象类Pet,封装属性name和sex,声明一个带有两个参数的构造函数,声明抽象方法void talk()和void eat();
声明一个Dog类继承自Pet,封装属性color,声明带有三个参数的构造函数,复写talk()和eat()方法;
声明一个Cat类继承自Pet,封装属性weight,声明带有三个参数的构造函数,复写talk()和eat()方法;
编写测试类,通过有参构造函数实例化Dog类对象,调用talk()方法和eat()方法;通过有参构造函数实例化Cat类对象 ,调用talk()方法和eat()方法;
具体输出要求请看测试说明。
测试说明
测试输入:
泰迪
male
brown
波斯猫
male
2.5
预期输出:
名称:泰迪,性别:male,颜色:brown,汪汪叫
泰迪吃骨头!
名称:波斯猫,性别:male,体重:2.5kg,喵喵叫
波斯猫吃鱼!`
package case1;
import java.util.Scanner;
public class Task1 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
String dogName = sc.next();
String dogSex = sc.next();
String dogColor = sc.next();
String catName = sc.next();
String catSex = sc.next();
double catWeight = sc.nextDouble();
// 通过有参构造函数实例化Dog类对象dog
// dog调用talk()方法
// dog调用eat()方法
/********* begin *********/
Dog dog=new Dog(dogName,dogSex,dogColor);
dog.talk();
dog.eat();
/********* end *********/
// 通过有参构造函数实例化Cat类对象cat
// cat调用talk()方法
// cat调用eat()方法
/********* begin *********/
Cat cat=new Cat(catName,catSex,catWeight);
cat.talk();
cat.eat();
/********* end *********/
}
}
// 抽象类Pet 封装属性name和sex
// 构造函数初始化name和sex
// 声明抽象方法talk()
// 声明抽象方法eat()
abstract class Pet {
/********* begin *********/
String name;
String sex;
Pet(String name,String sex){
this.name=name;
this.sex=sex;
}
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
public String getSex()
{
return sex;
}
public void setSex(String sex)
{
this.sex = sex;
}
abstract void talk();
abstract void eat();
/********* end *********/
}
// Dog类继承自Pet类 封装属性color
// 构造函数初始化name、sex和color
// talk()输出'名称:name,性别:sex,颜色:color,汪汪叫'
// eat()输出'name吃骨头'
class Dog extends Pet {
/********* begin *********/
private String color;
Dog(String name,String sex,String color){
super(name,sex);
this.color=color;
}
void talk(){
System.out.println("名称:"+getName()+",性别:"+getSex()+",颜色:"+color+",汪汪叫");
}
void eat(){
System.out.println(name+"吃骨头!");
}
/********* end *********/
}
// Cat类继承自Pet类 封装属性weight
// 构造函数初始化name、sex和weight
// 实现自己的talk()方法和eat()方法
// talk()输出'名称:name,性别:sex,体重:weight kg,喵喵叫'
// eat()输出'name吃鱼'
class Cat extends Pet {
/********* begin *********/
private double weight;
Cat(String name,String sex,double weight){
super(name,sex);
this.weight=weight;
}
void talk(){
System.out.println("名称:"+name+",性别:"+sex+",体重:"+weight+"kg,喵喵叫");
}
void eat(){
System.out.println(getName()+"吃鱼!");
}
/********* end *********/
}