继承
- 作用:还原客观世界中事物与事物的一种 is a 关系。
1 is a 关系
- 即什么是一种什么,如图所示:
- 比如:
鸟 是一种 动物 , 鸟 is a 动物。 香蕉 是一种 水果, 香蕉 is a 水果。 机械键盘 是一种 键盘 是一种 工具 , 机械键盘 is a 键盘 is a 工具。
- 当 is a 关系成立时,前者一定具备后者的特征与行为。
2 java中的is a关系
- 特点:
1. java中 is a 关系,称之为继承,继承关系是一种类与类的is a 关系。 2. 前者称为子类、派生类,后者称为父类、超类、基类 子类 继承 父类 Dog is a Animal 3. 客观世界中如果is a 关系成立,前者一定具备后者的特征与行为,在java中如果继承关系成立,子类一定具备父类的特征(属性)与行为(方法)。
3 建立继承关系的语法
- 语法如下:
class 子类 extends 父类{ }
演示的代码如下:
package com.txw.test;
class Animal{
// 特征(属性)
String name;
int age;
// 行为(方法)
public void eat(){
System.out.println("Animal eat");
}
public void sleep(){
System.out.println("Animal sleep");
}
}
// 在程序明确 Dog 与 Animal的is a关系
// Dog可以“获得”Animal类中的属性与方法
class Dog extends Animal{
// 游泳
public void swim(){
System.out.println("Dog swim");
}
// 叫
public void shout(){
System.out.println("Dog shout");
}
}
public class Test{
public static void main(String[] args) {
Dog d = new Dog();
// Dog类中没有定义eat,因为Dog extends Animal 就可以获得Animal中定义的属性与方法
d.eat();
// Dog类中没有定义sleep,因为Dog extends Animal 就可以获得Animal中定义的属性与方法
d.sleep();
d.swim();
d.shout();
}
}
- 建立继承关系的优势:提高代码的重用性,父类中的属性与方法可以直接共享给子类使用。
4 继承关系的特点
- 创建子类对象时JVM自动创建父类对象,父类对象会成为子类对象的一部分。如图所示:
将来通过子类引用就可以直接使用父类对象中的属性与方法。 - Java中的继承关系为单继承,一个类只能有一个直接父类,可以间接继承多个类。
演示的代码如下:
package com.txw.test;
// 太爷类
class MyClassA{
int a = 100;
}
// 爷爷类.
class MyClassB extends MyClassA{
int b = 200;
}
// 父类
class MyClassC extends MyClassB{
int c = 300;
}
// 子类
class MyClassD extends MyClassC{
int d = 400;
}
public class Test{
public static void main(String[] args) {
MyClassD mc = new MyClassD(); // 创建子类对象
System.out.println( mc.d ); // 本类中的d属性
System.out.println( mc.c ); // 父类中的c属性
System.out.println( mc.b ); // 爷爷类中的b属性
System.out.println( mc.a ); // 太爷类中的a属性
}
}
5 访问权限修饰符(重点)
-
控制组件的访问可见范围。
本类 同包 非同包子类 任意位置 private(私有的) T (default)(默认的) T T protected(受保护的) T T T public(公开的) T T T T 当组件前没有修饰符时默认为default。
6 方法覆盖(Override)
- 作用:父类是众多子类共性的抽取,只保留共性无法表达细节,父类提供的方法通用但不适用于所有子类,子类可以按照父类方法的声明在子类中重写一个,创建子类对象时不会再调用父类中的方法。
- 语法要求:
演示的代码如下:访问权限修饰符相同或更宽 返回值类型、方法名、参数表相同,不能比父类抛出更宽泛的异常。
class Animal{
// 特征(属性)
String name;
int age;
// 行为(方法)
public void eat(){
System.out.println("Animal eat");
}
}
// 在程序明确 Dog 与 Animal的is a关系
class Dog extends Animal {
// 父类的eat方法不再适用于子类
// 覆盖父类的方法
public void eat() {
System.out.println("趴着吃,爱啃骨头!");
}
}
7 Super关键字
- super表示父类对象的引用。
7.1 使用super.访问父类属性与方法
- 演示:使用super点解决成员变量命名冲突问题。
class Super{ int a = 100; // 父类属性 } class Sub extends Super{ int a = 50; // 子类属性 public void method(){ int a = 10;/ / 局部变量 // 使用父类属性 System.out.println( a ); // 直接使用(就近原则) System.out.println( this.a ); // 访问本类属性 System.out.println( super.a ); // 访问父类属性 } }
- 演示:在子类中调用父类被覆盖的方法
class Super{ public void m1(){ // 2000行代码 System.out.println("m1() in Super"); } } class Sub extends Super{ // 覆盖父类的m1 public void m1(){ // 使用父类m1方法中的2000行代码 super.m1(); // 调用被子类覆盖的方法 // 加入新代码 System.out.println("m1() in Sub"); } }
7.2 super() 告知JVM创建父类对象时调用什么构造方法
-
创建子类对象时JVM自动创建父类对象,父类对象会成为子类对象中的一部分。
-
JVM创建子类对象时默认调用父类无参构造方法。
-
由于JVM创建子类对象时默认依赖父类的无参构造方法,通常情况下一个类要有两个构造方法。
有参构造用于为属性赋值。
无参构造用于创建子类对象时使用。
演示的代码如下:class Super{ public Super(){ System.out.println("Super( )"); } public Super(int n){ System.out.println("Super( int )"); } } class Sub extends Super{ public Sub(){ } } new Sub(); // 输出结果:Super( )
-
为什么JVM创建对象时默认使用无参构造方法?
因为:在每个构造方法中的第一行都有一行隐含的代码super(),用来告知JVM创建父类对象时使用无参构造方法。
演示的代码如下:class Sub extends Super{ public Sub(){ // 隐藏代码 super(); // 告知JVM创建父类对象时,使用父类无参构造 } public Sub(int n){ } }
-
通过super()让JVM在创建父类对象时使用父类的其他构造方法
演示的代码如下:class Super{ public Super(){ System.out.println("Super( )"); } public Super(int n){ System.out.println("Super( int )"); } public Super(String str){ System.out.println("Super( String ) "); } } class Sub extends Super{ public Sub(){ // 隐藏代码 // super(); // 告知JVM创建父类对象时,使用父类无参构造 // super(10); // 告知JVM创建父类对象时,使用参数类型为int类型的构造方法 super("ABC"); // 告知JVM创建父类对象时,使用参数类型为String类型的构造方法 } }
演示:在封装场景下,使用父类构造方法为父类属性赋值。
class Animal{ private String name; private int age; public Animal(){System.out.println("Animal( )");} public Animal(String name,int age){ System.out.println("Animal( String,int )"); this.name = name; this.age = age; } public void setName(String name){ this.name = name; } public String getName(){ return name; } public void setAge(int age){ this.age = age; } public int getAge(){ return age; } } // 在程序明确 Dog 与 Animal的is a关系 class Dog extends Animal{ public Dog(){} public Dog(String name,int age){ super(name,age) ;// 使用父类构造方法,为父类属性赋值 // s uper.setName(name); // 使用父类set方法赋值 // super.setAge(age); } } public class Test{ public static void main(String[] args) { Dog d = new Dog("森森",18); // d.setName("森森"); // d.setAge(18); System.out.println( d.getName() ); System.out.println( d.getAge() ); } }
8 创建对象的过程
-
步骤:
1. 分配空间(父类+子类) 2. 初始化父类属性 3. 调用父类构造方法 4. 初始化子类属性 5. 调用子类构造方法 如果继承为多级继承2~3循环执行
演示的代码如下:
package com.txw.test;
class MyClassA{ // 太爷类
public MyClassA(){
System.out.println("MyClassA( )");
}
}
class MyClassB extends MyClassA {// 爷爷类
public MyClassB(){
System.out.println("MyClassB( )");
}
}
class MyClassC extends MyClassB{ // 父类
public MyClassC(){
System.out.println("MyClassC( )");
}
}
class MyClassD extends MyClassC{ // 子类
public MyClassD(){
System.out.println("MyClassD( )");
}
}
public class Test{
public static void main(String[] args) {
new MyClassD();
}
}
打印结果如图所示:
9 习题
- (继承)关于继承描述错误的是(B) 。
A. 继承体现的是类与类之间的"is-a"关系。
B. 通过继承,子类可以直接访问父类中所有的属性和方法。
C. Java 中的继承是单继承的关系 D. 父类是子类共性的提取。
原因:父类中私有的属性和方法是继承不到的。 - (修饰符)下列关于访问修饰符访问权限描述错误的是© 。
A. private :只能在本类中使用。
B. default :本类+同包。
C. protected :本类+同包+不同包。
D. public: 本类+同包+不同包。
原因:protected本类+同包+非同包父子类。 - (覆盖)下列关于方法覆盖描述错误的是(BD) 。
A. 子类中的方法名必须和父类中方法名相同。
B. 子类中的方法参数列表和父类的不同 。
C. 子类中的方法返回值类型和父类相同。
D. 父类的方法访问修饰符和子类中的相同或是更宽。
原因:B选项错误,覆盖子类中的方法参数应该和父类一致。
D选项错误,子类覆盖子类方法修饰符的权限应该和父类的一致要么比父类更宽。 - (继承)关于 Java 中的继承,以下说法正确的是© 。
A. 一个子类可以有多个直接的父类,一个父类也可以有多个直接的子类。
B. 一个子类可以有多个直接的父类,但是一个父类只可以有一个直接的子类。
C. 一个子类只能有一个直接的父类,但是一个父类可以有多个直接的子类 。
D. 以上说法都不对 。
原因:一个子类只能直接继承一个父类,而一个父类可以有多个子类。 - (覆盖)仔细阅读以下代码,写出代码执行的结果:
package com.txw.test;
class Super{
public Super(){
System.out.println("Super()");
}
public Super(String str){
System.out.println("Super(String)");
}
}
class Sub extends Super{
public Sub(){
System.out.println("Sub()");
}
public Sub(int i){
this();
System.out.println("Sub(int)");
}
public Sub(String str){
System.out.println("Sub(String)");
}
}
public class Test{
public static void main(String[] args) {
Sub s1= new Sub();
Sub s2= new Sub(10);
Sub s3= new Sub("hello");
}
}
答:
(1) Super(),Sub()
(2) Super(),Sub(),Sub(int)
(3) Super(String),Sub(String)
创建子类对象优先构建父类对象。
6. (super)仔细阅读以下程序,请问如何修改代码才能通过?
class Super{}
class Sub extends Super{
public Sub(){ }
public Sub(String str){
super(str);
}
}
答:public Super() public Super(String str)
Sub类中访问了Super类中的有参构造和无参构造,Super类中没有有参构造需要提供,当一个类中显示提供了构造方法编译 器就不会默认提供无参构造,所有提供有参构造的同时需要提供无参构造。
7. (super)仔细阅读以下代码,写出代码执行的结果。
package com.txw.test;
class Super{
public void m1(){
System.out.println("m1() in Super");
}
public void m2(){
System.out.println("m2() in Super");
}
}
class Sub extends Super{
public void m1(){
System.out.println("m1() in Sub");
super.m1();
}
}
public class TestSuperSub{
public static void main(String[] args) {
Sub s= new Sub();
s.m1();
s.m2();
}
}
答: m1() in Sub, m1() in Super, m2() in Super。
8. (多态)仔细阅读以下代码,编译是否通过,如果通过,写出输出结果;如果不能通过,则如何修改?
package com.txw.test;
class Super{
public void method(){
System.out.println("method() in Super");
}
public void method(int i ){
System.out.println("method(int) in Super");
}
}
class Sub extends Super{
public void method(){
System.out.println("m1() in Sub");
}
public void method(String str){
System.out.println("method(String) in Sub");
}
}
public class TestSuperSub{
public static void main(String[] args) {
Super s= new Sub();
s.method(10);
s.method();
s.method("hello");
}
}
答:. 不能通过编译,因为使用父类引用指向子类对象,该引用只能调用父类中定义的方法,super类中method方法没有接收 String类型的,所有报错。 修改:Super s = new Sub(); Sub sub = (Sub)s; sub.method(“hello”);
9. (多态)仔细阅读以下代码,写出程序运行之后输出的结果。
package com.txw.test;
class Super{
public void m(){
System.out.println("m() in Super");
}
}
class Sub extends Super{
public void m(){
System.out.println("m() in Sub");
}
}
public class TestSuperSub{
public static void foo(Super s){
s.m();
}
public static void main(String[] args) {
Sub sub = new Sub();
Super sup = new Super();
foo(sub);
foo(sup);
}
}
答: m() in Super , m() in Sub。
10. (访问修饰符)仔细阅读以下代码,描述正确的是(D.E) 。
package com.txw.test;
public class MyClass{
int value;
}
import com.txw.test;
MySubClass extends MyClass{
public MySubClass(int value){
this.value = value;
}
}
A. 编译通过 。
B. 编译不通过,应把第 12 行改成 super.value = value;
C. 编译不通过,应把第 12 行改成 super(value);
D. 编译不通过,可以为 MySubClass 增加一个 value 属性。
E. 编译不通过,把第 4 行改为 protected int value; 把第 12 行改为 super.value = value;
11 (访问修饰符)仔细阅读以下代码,以下代码有哪些地方编译出错?假设不允许修改 MyClass 类, 那应该如何修改?
答:
TestMyClass1 和 TestMyClass2 都有错
(1) // TestMyClass1.java
package corejava.chp7;
public class TestMyClass1{
public static void main(String args[]){
MyClass mc1 = new MyClass();
MyClass mc2 = new MyClass(10);
System.out.println(mc1.value); // 应改 mc1.getValue()
System.out.println(mc2.value); // 应改 mc2.getValue()
}
}
(2)// TestMyClass2.java
ppublic class TestMyClass2{
public static void main(String args[]){
MyClass mc1 = new MyClass();
MyClassmc2 = newMyClass(10); // 此处错误,带参数的构造方法在非同包的类中不能访问
System.out.println(mc1.value); // 应改为 mc1.getValue()
System.out.println(mc2.value); // 应改 mc2.getValue()
}
}
- (覆盖)阅读以下代码,哪些代码写在//1 处,程序编译能通过(A,C) 。
package com.txw.test;
class Super{
int method(){
return 0;
}
}
class Sub extends Super{
// 1
}
A. public int method(){return 0;}
B. void method(){}
C. void method(int n){}
D. protected void method(){}
13. (对象创建过程)仔细阅读以下代码,写出代码的执行结果:
package com.txw.test;
class Meal{
public Meal(){
System.out.println(" Meal()");
}
}
class Lubch extends Meal{
public Lubch(){
System.out.println("Lubch()");
}
}
class Vegetable{
public Vegetable(){
System.out.println(" Vegetable()");
}
}
class Potato extends Vegetable{
public Potato(){
System.out.println("Potato()");
}
}
class Tomato extends Vegetable{
public Tomato(){
System.out.println("Tomato()");
}
}
class Meat{
public Meat(){
System.out.println("Meat()");
}
}
class Sandwich extends Lubch{
Potato p = new Potato();
Meat m = new Meat();
Tomato t = new Tomato();
public Sandwich(){
System.out.println("Sandwich()");
}
}
public class TestSandwich{
public static void main(String[] args) {
Sandwich sandwich = new Sandwich();
}
}
答:输出结果为: Meal() Lunch() // 递归构造父类对象 Vegetable() Potato() //Potato 属性 Meat() //Meat 属性 Vegetable() Tomato() //Tomato 属性 Sandwich()//本类构造方法.
14. (覆盖)阅读以下代码,哪些代码写在//1 处,程序编译能通过(ABCD)。
package com.txw.test;
class Super {
private void method(){
}
}
class Sub extends Super{
// 1
}
A. public int method(){return 0;}
B. void method(){}
C. void method(int n){}
D. private void method(){}
原因:父类方法私有修饰,子类继承不到所以四个选项都正确。
15. (多态)仔细阅读以下代码,下列几个选项中,有哪几个放在//1 位置能够编译通过(ABCD)。
A. return null;
B. return new Animal();
C. return new Dog();
D. return new Cat();
原因:所有引用类型作为返回值类型都可以返回null,能够通过编译。 返回值类型是Animal,可以返回本类对象+所有子类对象。
16. (封装)编程:定义一个 Dog 类,类中属性有名字、年龄、性别(true-公),要求如下:
(1) 对类进行封装,并提供 get/set 方法 。
(2) 提供一个无参数的构造方法和一个带有三个参数的构造方法 。
(3) 定义一个测试类,创建对象,并对属性赋值,并将对象的信息打印在控制台上 。
演示的代码如下:
package com.txw.test;
public class Test {
public static void main(String[] args) {
Dog d = new Dog("藏獒", 5, true);
System.out.println(d.getName()+" "+d.getAge()+" "+d.getSex());
}
}
class Dog{
private String name; // 姓名
private int age; // 年龄
private boolean sex; // 性别
public String getName() {
return name; }
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public boolean getSex() {
return sex;
}
public void setSex(boolean sex) {
this.sex = sex;
}
public Dog() { super();
// TODO Auto-generated constructor stub
}
public Dog(String name, int age, boolean sex) {
super();
this.name = name;
this.age = age;
this.sex = sex;
}
}
- (封装)编程:定义一个网络用户类(User 类),需要处理的信息有用户 ID、用户密码 password、邮箱 地址(email),要求如下: (1) 对类进行封装,提供 get/set 方法。
(2) 提供带有两个参数的构造方法,为用户 ID 和用户密码赋值,此时 email 采用默认的:用户名 加上”@zparkhr.com.cn”; 同时提供带有三个参数的构造方法。
(3) 定义一个测试类,创建对象,并展示用户的信息。
演示的代码如下:
package com.txw.test;
public class Test {
public static void main(String[] args) {
User u = new User("gj", "12354");
System.out.println(u.getID() + " " + u.getPassworld() + " " + u.getEmail());
}
}
class User {
// 属性私有提供set/get
private String ID;
private String passworld; // 密码
private String email; // 邮箱
public String getID() {
return ID;
}
public void setID(String iD) {
ID = iD;
}
public String getPassworld() {
return passworld;
}
public void setPassworld(String passworld) {
this.passworld = passworld;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
/**
* @param iD
* @param passworld
*/
public User(String iD, String passworld) {
super(); ID = iD;
this.passworld = passworld; email = iD + "@zparkhr.com.cn";
}
}
- (封装)编程:定义一个 Book 类(代表教材),具有属性名称(title)、页数(pageNum),要求如下:
(1) 对类进行封装,属性私有化,并提供公开的 get/set 方法;其中要求页数不能少于 200 页,否 则输出”错误信息”,并赋予默认值 200 。
(2) 提供无参数和有参数的构造方法。
(3) 编写一个测试类,创建对象并为属性赋值,将对象的信息展示在控制台上。
演示的代码如下:
package com.txw.test;
public class Test {
public static void main(String[] args) {
Book b = new Book("疯狂java讲义", 600);
System.out.println(b.getTitle() + " " + b.getPageNum());
}
}
// 图书
class Book {
private String title; // 名称
private int pageNum; // 页数
// 属性私有提供set/get
public String getTitle() {
return title; }
public void setTitle(String title) {
this.title = title;
}
public int getPageNum() {
return pageNum;
}
public void setPageNum(int pageNum) {
// 页数不能少于200页,否则输出"错误信息"并赋值200
if (pageNum < 200) {
System.out.println("错误信息");
this.pageNum = 200;
} else {
this.pageNum = pageNum;
}
}
public Book() {
super();
}
public Book(String title, int pageNum) {
super(); this.title = title; this.pageNum = pageNum;
}
}
- (封装)编程:已知一个 Student 类,代码如下:
package com.txw.test;
class Student{
String name;
int age;
String address;
String zipCode;
String mobile;
}
(1) 将 Student 类进行封装,即属性均私有化,并提供 get/set 方法。
(2) 为 Student 类添加一个 getPostAddress 方法,要求返回 Student 对象的地址和邮编。
(3) 定义一个测试类,创建对象并为属性赋值,将用户的信息进行展示。
演示的代码如下:
package com.txw.test;
public class Test {
public static void main(String[] args) {
Student s = new Student();
s.setName("gj"); s.setAge(17);
s.setAddress("百知教育");
s.setZipCode("100000");
s.setMobile("11111111111222");
System.out.println(s.getName() + " " + s.getAge() + " " + s.getAddress() + " " + s.getZipCode() + " " + s.getMobile());
}
}
class Student {
// 属性私有提供set/get
private String name; // 姓名
private int age; // 年龄
private String address; // 住址
private String zipCode; // 邮编
private String mobile; // 手机号
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getZipCode() {
return zipCode;
}
public void setZipCode(String zipCode) {
this.zipCode = zipCode;
}
public String getMobile() {
return mobile;
}
public void setMobile(String mobile) {
this.mobile = mobile;
}
// 返回学生的地址和邮编
public Address getPostAddress() {
// 一个方法只能返回一个数据,需求需要返回两个数据,解决办法将这两个数据放到一个对象中返回该对象即 可,所以定义了Address类
return new Address(address, zipCode);
}
}
class Address {
String address;
String zipCode;
public Address(String address, String zipCode) {
super(); this.address = address; this.zipCode = zipCode;
}
}
- (继承+封装)编程:定义一个人类(Person),包括属性:姓名、性别、年龄、国籍; 包括的方法:吃饭、睡觉,工作 。
(1) 根据人类,定义一个子类,增加属性:学校、学号;重写工作方法(实现内容为学习) 。
(2) 根据人类,定义一个工人类,增加属性:单位,工龄;重写工作方法。
(3) 根据学生类,定义一个学生干部类(StudentLeader),增加属性:职务;增加方法:开会 。
(4) 定义一个测试类,分别创建上述 3 类具体人物的对象并将信息打印在控制台上。
演示的代码如下:
package com.txw.test;
public class Test {
public static void main(String[] args) {
Student s = new Student();
s.name = "gj";
s.age = 17;
s.number = "BZ001";
s.nationality = "中国";
s.school = "理工";
s.sex = "男";
System.out.println(s.name + " " + s.age + " " + s.number + " " + s.nationality + " " + s.school + " " + s.sex);
Worker w = new Worker();
w.name = "gj";
w.age = 18;
w.nationality = "中国";
w.sex = "男";
w.workUnit = "学无止路";
w.workingYears = 2;
System.out.println(s.name + " " + w.age + " " + w.nationality + " " + w.sex + " " + w.workUnit + " " + w.workingYears);
StudentLeader ss = new StudentLeader();
ss.name = "gj";
ss.age = 18;
ss.sex = "男";
ss.nationality = "中国";
ss.duty = "组长";
ss.number = "BZ001";
System.out.println(ss.name + " " + ss.age + " " + ss.sex + " " + ss.nationality + " " + ss.duty + " " + ss.number);
// 统计学生干部个数
int count = 0;
// 定义Person类型数组存储,学生对象,学生干部对象,工人对象
Person[] p = {s,ss,w};
for(int i = 0; i < p.length ; i++){
// 遍历得到每一个元素如果是学生干部统计变量+1
if(p[i] instanceof StudentLeader){
count++;
StudentLeader sl = (StudentLeader)p[i];
System.out.println(sl.name + " " + sl.age + " " + sl.sex + " " + sl.nationality + " " + sl.duty + " " + sl.number);
}
// 如果是学生对象打印所有信息
if(p[i] instanceof Student){
Student st = (Student)p[i];
System.out.println(st.name + " " + st.age + " " + st.number + " " + st.nationality + " " + st.school + " " + st.sex);
}
}
System.out.println(count);
}
}
class Person { String name;
String sex;
int age;
String nationality; // 国籍
// 吃
public void eat() {
}
// 睡觉
public void sleep() {
}
// 工作
public void work() {
}
}
class Student extends Person {
String school; // 学校
String number; // 学号
// 覆盖父类中的方法
@Override
public void work() {
System.out.println("学习");
}
}
// 工人类
class Worker extends Person {
String workUnit; // 单位
int workingYears; // 工龄
// 覆盖父类中的方法
@Override
public void work() {
System.out.println("上班");
}
}
// 学生干部类
class StudentLeader extends Student {
String duty; // 职务
// 开会方法
public void meet() {
System.out.println("管培生会议");
}
}
- (多态)在上一个题目的基础上,定义一个 Person 类型的数组,存储多个不同类型的子类型对象,
(1) 统计并打印输出数组中所有学生干部的个数。
(2) 打印输出所有学生的信息。
演示的代码如下:
package com.txw.test;
public class Test {
public static void main(String[] args) {
Student s = new Student();
s.name = "gj";
s.age = 17;
s.number = "BZ001";
s.nationality = "中国";
s.school = "理工";
s.sex = "男";
System.out.println(s.name + " " + s.age + " " + s.number + " " + s.nationality + " " + s.school + " " + s.sex);
Worker w = new Worker();
w.name = "gj";
w.age = 18;
w.nationality = "中国";
w.sex = "男";
w.workUnit = "学无止路";
w.workingYears = 2;
System.out.println(s.name + " " + w.age + " " + w.nationality + " " + w.sex + " " + w.workUnit + " " + w.workingYears);
StudentLeader ss = new StudentLeader();
ss.name = "gj";
ss.age = 18;
ss.sex = "男";
ss.nationality = "中国";
ss.duty = "组长"; ss.number = "BZ001";
System.out.println(ss.name + " " + ss.age + " " + ss.sex + " " + ss.nationality + " " + ss.duty + " " + ss.number);
// 统计学生干部个数
int count = 0;
// 定义Person类型数组存储,学生对象,学生干部对象,工人对象
Person[] p = {s,ss,w}; for(int i = 0; i < p.length ; i ++){
// 遍历得到每一个元素如果是学生干部统计变量+1
if(p[i] instanceof StudentLeader){
count++;
StudentLeader sl = (StudentLeader)p[i];
System.out.println(sl.name + " " + sl.age + " " + sl.sex + " " + sl.nationality + " " + sl.duty + " " + sl.number);
}
// 如果是学生对象打印所有信息
if(p[i] instanceof Student){
Student st = (Student)p[i];
System.out.println(st.name + " " + st.age + " " + st.number + " " + st.nationality + " " + st.school + " " + st.sex);
}
}
System.out.println(count);
}
}
class Person {
String name;
String sex;
int age;
String nationality; // 国籍
// 吃
public void eat() {
}
// 睡觉
public void sleep() {
}
// 工作
public void work() {
}
}
class Student extends Person {
String school; // 学校
String number; // 学号
//覆盖父类中的方法
@Override
public void work() {
System.out.println("学习");
}
}
// 工人类
class Worker extends Person {
String workUnit; // 单位
int workingYears; // 工龄
//覆盖父类中的方法
@Override
public void work() {
System.out.println("上班");
}
}
// 学生干部类
class StudentLeader extends Student {
String duty; // 职务
// 开会方法
public void meet() {
System.out.println("管培生会议");
}
}
- (继承+封装)编程:定义一个交通工具类(Vehicles),该类的属性为:商标(brand)、颜色(color);功 能方法为:run 方法(行驶功能,控制台输出“车已经启动”)、showInfo(显示信息,控制台输出商 标和颜色)。
(1) 编写一个小汽车类(Car)继承于 Vehicles 类,添加属性座位(seats);成员方法 showCar(显示小 汽车的所有信息)。
(2) 编写一个卡车类(Truck)继承于 Vehicles 类,添加属性载重(load);成员方法 showTruck(显示卡 车的所有信息)。
(3) 定义测试类,分别创建 Car 对象和 Truck 对象,控制台打印输出的信息如下: 商标:奔驰,颜色:白色,座位:5 商标:福田,颜色:红色,载重:6.5 吨。
演示的代码如下:
package com.txw.test;
public class Test {
public static void main(String[] args) {
Car c = new Car();
c.brand = "奔驰";
c.color = "白色";
c.seats = 5;
c.showCar();
Truck t = new Truck();
t.brand = "福田";
t.color = "红色";
t.load = 6.5;
t.showTruck();
}
}
// 交通工具
class Vehicles{
String brand; // 品牌
String color; // 颜色
// 行驶的方法
public void run(){
System.out.println("车已经启动");
}
// 展示信息的方法
public void showInfor(){
System.out.println(brand+" "+color);
}
}
// 汽车类
class Car extends Vehicles{
int seats; // 座位数
// 展示小汽车的信息
public void showCar(){
System.out.println("品牌: "+brand+" ,颜色: "+color+" ,座位数: "+seats);
}
}
// 卡车类
class Truck extends Vehicles{
double load; // 载重
// 展示卡车信息
public void showTruck(){
System.out.println("品牌: "+brand+" ,颜色: "+color+" ,载重: "+load+"吨");
}
}
- 编程:有以下几个类,根据下面的继承关系,用 Java 代码实现:
(1) Circle 类(圆形),属性:半径;方法:求周长、求面积 。
(2) Rect 类(矩形),属性:长、宽;方法:求周长、求面积 。
(3) Square 类(正方形),属性:边长;方法:求周长、求面积 提示: ① 这三个类均具有求周长和面积的方法 ② 正方形是特殊的矩形 。
演示的代码如下:
package com.txw.test;
// Shape类中必须定义girth方法和area方法。
// 目的是为了能够针对Shape类型的引用调用这两个方法。
// 要注意的是,求周长和求面积的方法都不带参数。
// 这两个方法表示求当前图形的周长或面积。
// 既然是当前图形,则必然有相应的属性。
//(例如,圆形有半径属性,正方形有边长属性)。
// 在求周长和面积时,只需要使用对象的属性,而不需要额外传递参数。
// 图形类
class Shape{
// 求周长
public double girth(){
return 0;
}
// 求面积
public double area(){
return 0;
}
}
// 圆形
class Circle extends Shape{
private double radius; // 半径
private double pi = 3.1415926;
public Circle(double radius) {
this.radius = radius;
}
public double area() {
return pi * radius * radius;
}
public double girth() {
return 2 * pi * radius;
}
}
// 矩形
class Rect extends Shape{
private double a; // 长
private double b; // 宽
public Rect(){
}
public Rect(double a, double b) {
this.a = a;
this.b = b;
}
public double area() {
return a*b;
}
public double girth() {
return 2*(a+b);
}
}
// 正方形
class Square extends Rect{
private double a; // 边长
public Square(double a) {
super();
this.a = a;
}
public double area() {
return a * a;
}
public double girth() {
return 4 * a;
}
}
- 编程:在上一题的基础上,创建一个长度为 3 的数组,里面有三个不同类型的对象,分别打印这三 个对象的周长和面积。
演示的代码如下:
package com.txw.test;
public class Test{
public static void main(String[] args){
Shape[] ss = new Shape[3];
ss[0] = new Circle(2);
ss[1] = new Rect(3,4);
ss[2] = new Square(3.5);
for(int i = 0; i<ss.length; i++){
System.out.println("girth : " + ss[i].girth() + "\t"+"area : " + ss[i].area());
}
}
}
- 编程:阅读以下代码,根据要求完成程序功能。
(1) 在程序的 1、2、3 处填上适当的 构造方法或 get/set 方法。
(2) 完成 4 处的填空:getAllDog 方法从一个 Animal 数组中挑选出所有的 Dog 对象,并把这 些对象放在一个 Dog 数组中返回 。
演示的代码如下:
package com.txw.test;
public class Test {
public static void main(String[] args) {
// 定义动物数组存储若干狗和猫对象
Animal[] as = new Animal[] {
new Dog("pluto"), new Cat("Tom"), new Dog("Snoopy"), new Cat("Garfield")};
Dog[] dogs = getAllDog(as);
for (int i = 0; i < dogs.length; i++) {
System.out.println(dogs[i].getName());
}
}
// 将动物数组中所有的狗存储在dog数组中进行返回
public static Dog[] getAllDog(Animal[] as) {
// 统计Dog的个数
int sumDog = 0;
for (int i = 0; i < as.length; i++) {
// 循环遍历得到动物数组中每一个元素,判断当前元素是否是Dog类型
if (as[i] instanceof Dog) {
// 如果是狗统计变量+1 sumDog++;
}
}
// 创建Dog数组,统计变量就是狗的数量,使用sumDog作为狗数组的长度
Dog[] dogs = new Dog[sumDog];
// 定义下标
int dogIndex = 0;
for (int i = 0; i < as.length; i++) { // 重新遍历动物数组找到dog对象
if (as[i] instanceof Dog) {
// 将dog对象存储在dog数组中
dogs[dogIndex] = (Dog) as[i];
// 第一次存储下标是0,每次存储成功后下标加1,指向下一个数组空间
dogIndex++;
}
}
return dogs;
}
}
// 动物类
class Animal {
//属性私有提供set/get
private String name; // 名称
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
// 狗继承动物
class Dog extends Animal {
public Dog(String name) {
setName(name);
}
}
// 猫继承动物
class Cat extends Animal {
public Cat(String name) {
setName(name);
}
}
- 编程:某公司的雇员分为以下若干类:
(1) Employee:这是所有员工总的父类。
① 属性:员工的姓名,员工的生日月份 。
② 方法:getSalary(int month) 根据参数月份来确定工资,如果该月员工过生日,则公司会 额外奖励 100 元。
(2) SalariedEmployee:Employee 的子类,拿固定工资的员工。
① 属性:月薪。
(3) HourlyEmployee:Employee 的子类,按小时拿工资的员工,每月工作超出 160 小时的部分 按照 1.5 倍工资发放。
① 属性:每小时的工资、每月工作的小时数。
(4) SalesEmployee:Employee 的子类,销售,工资由月销售额和提成率决定。
① 属性:月销售额、提成率。
(5) BasePlusSalesEmployee:SalesEmployee 的子类,有固定底薪的销售人员,工资由底薪加 上销售提成部分。
① 属性:底薪。 要求:
(1) 创建 SalariedEmployee、HourlyEmployee、SaleEmployee、BasePlusSalesEmployee 四个类的对象各一个。
(2) 并调用父类 getSalary(int money)方法计算某个月这四个对象各自的工资 注意:要求把每个类都做成完全封装,不允许非私有化属性。 类图如下:
演示的代码如下:
package com.txw.test;
// 1.name和birthMonth是每个员工都应该具有的属性,因此应当放在Employee类中。
// 2.子类无法直接访问这两个属性,但是可以利用super()在构造方法中设置父类的属性。
// 3.判断员工是否过生日的逻辑也是所有员工都有的逻辑。这个逻辑应当写在Employee类。
// 4. 类的getSalary方法应当利用super.getSalary来调用父类的getSalary方法
public class TestEmployee {
public static void main(String[] args) {
Employee[] es = new Employee[4];
es[0] = new SalariedEmployee("John", 5, 5000);
es[1] = new HourlyEmployee("Tom", 10, 25, 170);
es[2] = new SalesEmployee("Lucy", 7, 200000, 0.03);
es[3] = new BasePlusSalesEmployee("James", 8, 1000000, 0.02, 5000);
for(int i = 0; i < es.length; i ++){
System.out.println(es[i].getSalary(5));
}
}
}
class Employee{
private String name;// 员工姓名
private int birthMonth; // 员工生日月份
public Employee(String name,int birthMonth){
this.name=name;
this.birthMonth=birthMonth;
}
public String getName(){
return name;
}
public double getSalary(int month){
if (this.birthMonth == month)
return 100;
else
return 0;
}
}
// 拿固定工资员工
class SalariedEmployee extends Employee{
private double salary; // 月薪
public SalariedEmployee(String name,int birthMonth,double salary){
// 把name,birthMonth两个参数传给父类,设置父类属性
super(name,birthMonth); this.salary=salary;
}
public double getSalary(int month){
// 调用父类的getSalary方法(判断是否生日),并加上月工资
return salary+super.getSalary(month);
}
}
// 小时工
class HourlyEmployee extends Employee{
private double salaryPerHour; // 每小时多少钱
private int hours; // 工作小时数
public HourlyEmployee(String name, int birthMonth, double salaryPerHour, int hours) {
super(name, birthMonth);
this.salaryPerHour = salaryPerHour;
this.hours = hours;
}
public double getSalary(int month){
double result=0;
//工作时间在160小时内正常发放,如果超出160小时,超出部分1.5倍发放。
if (hours>160)
result = 160 * this.salaryPerHour + (hours - 160) * this.salaryPerHour * 1.5;
else result = this.hours*this.salaryPerHour;
// 最终工资+是否是生日
return result + super.getSalary(month);
}
}
// 销售
class SalesEmployee extends Employee{
// 月销售单数 每一单多小钱
private double sales;
private double rate;
public SalesEmployee(String name, int birthMonth, double sales, double rate) {
super(name, birthMonth);
this.sales = sales;
this.rate = rate;
}
// 总单数*每单钱数
public double getSalary(int month) {
return this.sales * this.rate + super.getSalary(month);
}
}
// 有底薪的销售
class BasePlusSalesEmployee extends SalesEmployee{
private double basedSalary; // 底薪
public BasePlusSalesEmployee(String name, int birthMonth, double sales, double rate, double basedSalary) {
super(name, birthMonth, sales, rate);
this.basedSalary = basedSalary; }
// 底薪+单数*每单钱数+是否是生日
public double getSalary(int month) {
return this.basedSalary+super.getSalary(month);
}
}
- 编程:在上一题的基础上,创建一个 Employee 数组,分别创建若干不同的 Employee 对象,并打 印某个月的工资。
演示的代码如下:
package com.txw.test;
// 1.name和birthMonth是每个员工都应该具有的属性,因此应当放在Employee类中。
// 2.子类无法直接访问这两个属性,但是可以利用super()在构造方法中设置父类的属性。
//3.判断员工是否过生日的逻辑也是所有员工都有的逻辑。这个逻辑应当写在Employee类。
// 4. 子类的getSalary方法应当利用super.getSalary来调用父类的getSalary方法
public class TestEmployee {
public static void main(String[] args) {
Employee[] es = new Employee[4];
es[0] = new SalariedEmployee("John", 5, 5000);
es[1] = new HourlyEmployee("Tom", 10, 25, 170);
es[2] = new SalesEmployee("Lucy", 7, 200000, 0.03);
es[3] = new BasePlusSalesEmployee("James", 8, 1000000, 0.02, 5000);
for(int i = 0; i<es.length; i++){ System.out.println(es[i].getSalary(5));
}
}
}
class Employee{
private String name; // 员工姓名
private int birthMonth; // 员工生日月份
public Employee(String name,int birthMonth){
this.name=name;
this.birthMonth=birthMonth;
}
public String getName(){
return name;
}
public double getSalary(int month){
if (this.birthMonth==month)
return 100;
else return 0;
}
}
// 拿固定工资员工
class SalariedEmployee extends Employee{
private double salary; // 月薪
public SalariedEmployee(String name,int birthMonth,double salary){
//把name,birthMonth两个参数传给父类,设置父类属性
super(name,birthMonth);
this.salary=salary;
}
public double getSalary(int month){
// 调用父类的getSalary方法(判断是否生日),并加上月工资
return salary+super.getSalary(month);
}
}
// 小时工
class HourlyEmployee extends Employee{
private double salaryPerHour; // 每小时多少钱
private int hours; // 工作小时数
public HourlyEmployee(String name, int birthMonth, double salaryPerHour, int hours) {
super(name, birthMonth);
this.salaryPerHour = salaryPerHour;
this.hours = hours;
}
public double getSalary(int month){
double result=0;
// 工作时间在160小时内正常发放,如果超出160小时,超出部分1.5倍发放。
if (hours > 160)
result = 160 * this.salaryPerHour + (hours - 160) * this.salaryPerHour * 1.5;
else
result = this.hours * this.salaryPerHour;
// 最终工资+是否是生日
return result + super.getSalary(month);
}
}
// 销售
class SalesEmployee extends Employee{
// 月销售单数 每一单多小钱
private double sales;
private double rate;
public SalesEmployee(String name, int birthMonth, double sales, double rate) {
super(name, birthMonth);
this.sales = sales;
this.rate = rate;
}
// 总单数*每单钱数
public double getSalary(int month) {
return this.sales * this.rate+super.getSalary(month);
}
}
// 有底薪的销售
class BasePlusSalesEmployee extends SalesEmployee{
private double basedSalary; // 底薪
public BasePlusSalesEmployee(String name, int birthMonth, double sales, double rate, double basedSalary) {
super(name, birthMonth, sales, rate);
this.basedSalary = basedSalary;
}
// 底薪+单数*每单钱数+是否是生日
public double getSalary(int month) {
return this.basedSalary+super.getSalary(month);
}
}
10 总结
如图所示: