三大特性之继承

继承

  • 作用:还原客观世界中事物与事物的一种 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 继承关系的特点

  1. 创建子类对象时JVM自动创建父类对象,父类对象会成为子类对象的一部分。如图所示:在这里插入图片描述
    将来通过子类引用就可以直接使用父类对象中的属性与方法。
  2. 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)(默认的)TT
    protected(受保护的)TTT
    public(公开的)TTTT

    当组件前没有修饰符时默认为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 习题

  1. (继承)关于继承描述错误的是(B) 。
    A. 继承体现的是类与类之间的"is-a"关系。
    B. 通过继承,子类可以直接访问父类中所有的属性和方法。
    C. Java 中的继承是单继承的关系 D. 父类是子类共性的提取。
    原因:父类中私有的属性和方法是继承不到的。
  2. (修饰符)下列关于访问修饰符访问权限描述错误的是© 。
    A. private :只能在本类中使用。
    B. default :本类+同包。
    C. protected :本类+同包+不同包。
    D. public: 本类+同包+不同包。
    原因:protected本类+同包+非同包父子类。
  3. (覆盖)下列关于方法覆盖描述错误的是(BD) 。
    A. 子类中的方法名必须和父类中方法名相同。
    B. 子类中的方法参数列表和父类的不同 。
    C. 子类中的方法返回值类型和父类相同。
    D. 父类的方法访问修饰符和子类中的相同或是更宽。
    原因:B选项错误,覆盖子类中的方法参数应该和父类一致。
    D选项错误,子类覆盖子类方法修饰符的权限应该和父类的一致要么比父类更宽。
  4. (继承)关于 Java 中的继承,以下说法正确的是© 。
    A. 一个子类可以有多个直接的父类,一个父类也可以有多个直接的子类。
    B. 一个子类可以有多个直接的父类,但是一个父类只可以有一个直接的子类。
    C. 一个子类只能有一个直接的父类,但是一个父类可以有多个直接的子类 。
    D. 以上说法都不对 。
    原因:一个子类只能直接继承一个父类,而一个父类可以有多个子类。
  5. (覆盖)仔细阅读以下代码,写出代码执行的结果:
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 类, 那应该如何修改?
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
答:

 TestMyClass1TestMyClass2 都有错 
(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. (覆盖)阅读以下代码,哪些代码写在//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;
    }
}
  1. (封装)编程:定义一个网络用户类(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";
    }
}
  1. (封装)编程:定义一个 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;
    }
}
  1. (封装)编程:已知一个 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;
    }
}
  1. (继承+封装)编程:定义一个人类(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("管培生会议");
    }
}
  1. (多态)在上一个题目的基础上,定义一个 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("管培生会议");
    }
}
  1. (继承+封装)编程:定义一个交通工具类(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+"吨");
    }
}
  1. 编程:有以下几个类,根据下面的继承关系,用 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;
    }
}
  1. 编程:在上一题的基础上,创建一个长度为 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) 在程序的 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. 编程:某公司的雇员分为以下若干类:
    (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);
    }
}
  1. 编程:在上一题的基础上,创建一个 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 总结

如图所示:
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

学无止路

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值