第十二章 继承
1.作业回顾
1,定义一个Person类(name,age,sno)进行数据封装,age的年龄范围设置为0到130,使用getAge返回年龄。
//1,定义一个Person类(name,age,sno)进行数据封装,age的年龄范围设置为0到130,使用getAge返回年龄。
public class Person {
private String name;
private int age;
private String sno;
public Person(String name, int age, String sno) {
super();
this.name = name;
this.sno = sno;
if(age <= 0 || age >=130) {
System.out.println("数据非法");
return;
}
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
if(age <= 0 || age >=130) {
System.out.println("数据非法");
return;
}
this.age = age;
}
public String getSno() {
return sno;
}
public void setSno(String sno) {
this.sno = sno;
}
}
public class Day121 {
public static void main(String[] args) {
Person p = new Person("张三", 20, "20191101");
System.out.println(p.getAge()); //20
p.setAge(-20); //数据非法
System.out.println(p.getAge()); //20
}
}
2,编写类Triangle,声明private的两个属性:底边长base和高height,同时提供getter和setter,在 TriangleManager类中定义一个方法public static double getArea(Triangle t)计算三角形的面积,并在main方法中输出。
public class Triangle {
//2,编写类Triangle,声明private的两个属性:底边长base和高height,同时提供getter和setter
private double base;
private double height;
public Triangle(double base, double height) {
super();
this.base = base;
this.height = height;
}
public double getBase() {
return base;
}
public void setBase(double base) {
this.base = base;
}
public double getHeight() {
return height;
}
public void setHeight(double height) {
this.height = height;
}
}
public class TriangleManager {
//TriangleManager类中定义一个方法public static double getArea(Triangle t)计算三角形的面积,并在main方法中输出。
public static double getArea(Triangle t) {
return t.getBase() * t.getHeight();
}
public static void main(String[] args) {
Triangle tr = new Triangle(3.0, 2.0);
double area = getArea(tr);
System.out.println(area);
}
}
2.成员变量的初始值
java中,局部变量( 形参、方法内定义的变量、代码块中定义的变量 )没有初始化不能使用。成员变量( 类变量 和 实例变量 )如果没有初始化会有默认值。
public class Day122 {
public static void main(String[] args) {
int i;
// System.out.println(i); //编译错误,i没有被初始化
}
}
class Foo{
//成员变量包括 类变量 和 实例变量
//类变量
static byte b;
//实例变量
short s;
char c;
int i;
long l;
float f;
double d;
boolean bool;
String str;
}
//java中一个类文件可以有多个类,但只能有一个public类
//public类的名称要与文件名相同
public class Day122 {
public static void main(String[] args) {
// int i; //局部变量
// System.out.println(i); //编译错误,i没有被初始化
Foo foo = new Foo();
System.out.println(Foo.b); //0 类变量通过类名访问
System.out.println(foo.s); //0 实例变量通过对象访问
System.out.println(foo.c); //
System.out.println(foo.i); //0
System.out.println(foo.l); //0
System.out.println(foo.f); //0.0
System.out.println(foo.d); //0.0
System.out.println(foo.bool); //false
//null表示它不引用任何对象
System.out.println(foo.str); //null String为引用类型,引用类型默认值为null
}
}
3.对象初始化
java中对象的初始化有三种方式:
1.在变量声明时赋值,
2.使用构造器,
3.使用代码块。
class Bar{
private String name = setDefaultName(); //声明变量的时候赋值
private int age = 0; //声明变量的时候赋值
//类变量
//记录创建对象的个数
public static int COUNT;
//静态代码块
//静态代码块在类被加载时执行
//每个类只被加载一次,因此静态代码块只执行一次
//静态代码块用来初始化静态字段(类变量)
//不能访问实例字段(实例变量)
static {
COUNT = 0;
System.out.println("1静态代码块执行");
}
//非静态代码块
//非静态代码块在每次创建对象的时候执行
//非静态代码块用来初始化实例字段(实例变量)
{
System.out.println("3非静态代码块执行");
COUNT++;
}
public Bar() {
System.out.println("4默认构造器执行");
}
private String setDefaultName() {
System.out.println("2setDefaultName()");
return "setDefaultName";
}
public Bar(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
}
public class Day123 {
public static void main(String[] args) {
//1.加载类,执行静态代码
//2.执行成员变量的赋值语句
//3.执行非静态代码块
//4.调用构造器
//ctrl + f查找和替换
Bar bar1 = new Bar();
System.out.println(bar1.getAge()); //0
System.out.println(bar1.getName()); //setDefaultName
System.out.println(Bar.COUNT); //1
//2.执行成员变量的赋值语句
//3.执行非静态代码块
//4.调用构造器
Bar bar2 = new Bar();
System.out.println(bar2.getAge()); //0
System.out.println(bar2.getName()); //setDefaultName
System.out.println(Bar.COUNT); //1
}
}
4.继承
java中通过继承一个类,来继承此类的所有功能。java中的每一个类都继承于Object类,当创建一个类时,会自动的继承Object类的所有方法。
//java中的所有类都继承于Object类
//类F继承于Object
class F{
}
public class Day124 {
public static void main(String[] args) {
//ctrl + shift + t 打开一种类型
//Ctrl + o 打开类的列表信息(属性和方法)
F f = new F();
//toString方法继承于Object
System.out.println(f.toString()); //day12.F@53bd815b
//hashCode方法继承于Object
//hashCode方法是本地方法,没有方法体
//native方法会调用底层的c语言的函数
//hashCode方法将返回对象的哈希码
System.out.println(f.hashCode()); //1404928347
//instanceof关键字用于判断一个对象是否是这个类型
//f是F类的实例
System.out.println(f instanceof F); //true
//f是Object类的实例
System.out.println(f instanceof Object); //true
//动物(Object)
//哺乳动物(F)
//f是某一只具体的哺乳动物(我家的狗——小黑)
}
}
Object类位于java.lang包中,它定义和实现了所有类的通用功能。在java中所有的类都继承于Object类。因此Object类是所有类的超类。
下面是继承的例子
//Person没有写继承,那么就自动继承Object类
class Person {
String name;
int age;
public void info() {
System.out.println("我叫" + name + ",我今年" + age + "岁了");
}
}
// extends 关键字用来继承一个类
// Student类是Person的子类,Person类是Student类的父类
// Student类继承了Person类中定义的属性和方法
// Student类有三个属性,两个方法
class Student extends Person {
// 学号
int sno;
public void study() {
System.out.println("好好学习,天天向上");
}
}
//Actor类继承于Person,一个父类可以有多个子类,一个子类只能有一个父类
class Actor extends Person {
// 薪水
double salary;
public void act() {
System.out.println("我热爱表演");
}
}
public class Day125 {
public static void main(String[] args) {
Student s = new Student();
//name和age属性继承于Person
s.name = "小明";
s.age = 10;
//sno是Student类中定义的属性
s.sno = 20191101;
//info方法继承于Person
s.info();
//study方法是Student类中定义的方法
s.study();
Actor a = new Actor();
//name和age属性继承于Person
a.name = "梁朝伟";
a.age = 50;
//salary是Student类中定义的属性
a.salary = 10000000;
//info方法继承于Person
a.info();
//act方法是Student类中定义的方法
a.act();
}
}
5.子类对象的实例化过程
子类对象创建之前必须先有父类对象 ,子类对象的构造器默认会调用父类的无参构造器,以便创建父类的对象。
class Person {
String name;
int age;
public Person() {
super(); //调用父类的无参构造器
System.out.println("Person构造器");
}
public void info() {
System.out.println("我叫" + name + ",我今年" + age + "岁了");
}
}
class Student extends Person {
//学号
int sno;
public Student( int sno) {
//子类对象创建之前必须先有父类对象
//子类对象的构造器默认会调用父类的无参构造器,以便创建父类对象
//super()调用父类的无参构造器
super(); //写不写都一样,默认会调用父类的无参构造器
System.out.println("Student构造器");
this.sno = sno;
}
public void study() {
System.out.println("好好学习,天天向上");
}
}
public class Day126 {
public static void main(String[] args) {
Student s = new Student(20191101); //创建两个对象,父类对象和子类对象
}
}
上面的例子中,子类的属性被初始化,但是父类的属性没有被初始化。
有个两种方式可以解决父类的属性初始化。
第一种:在子类的构造器中直接初始化从父类继承的属性。
class Person {
String name;
int age;
public Person() {
super(); //调用父类的无参构造器
System.out.println("Person构造器");
}
public void info() {
System.out.println("我叫" + name + ",我今年" + age + "岁了");
}
}
class Student extends Person {
//学号
int sno;
public Student(String name, int age, int sno) {
//子类对象创建之前必须先有父类对象
//子类对象的构造器默认会调用父类的无参构造器,以便创建父类对象
//super()调用父类的无参构造器
super(); //写不写都一样,默认会调用父类的无参构造器
System.out.println("Student构造器");
this.name = name;
this.age = age;
this.sno = sno;
}
public void study() {
System.out.println("好好学习,天天向上");
}
}
public class Day1261 {
public static void main(String[] args) {
Student s = new Student("小明", 10, 20190001); //创建两个对象,父类对象和子类对象
System.out.println(s.name); //张三
System.out.println(s.age); //30
System.out.println(s.sno); //20191101
}
}
第二种:调用父类的有参构造器进行初始化。(推荐)
class Person4 {
String name;
int age;
public Person4(String name, int age) {
this.name = name;
this.age = age;
System.out.println("Person4构造器");
}
public void info() {
System.out.println("我叫" + name + ",我今年" + age + "岁了");
}
}
class Student4 extends Person4 {
//学号
int sno;
public Student4(String name, int age, int sno) {
//调用父类的有参构造器,对name和age进行赋值
super(name, age);
this.sno = sno;
System.out.println("Student构造器");
}
public void study() {
System.out.println("好好学习,天天向上");
}
}
public class Day1262 {
public static void main(String[] args) {
Student4 s = new Student4("小明", 10 , 20190001); //创建两个对象,父类对象和子类对象
System.out.println(s.name);
System.out.println(s.age);
System.out.println(s.sno);
}
}
class Person5 {
String name;
int age;
public Person5(String name, int age) {
this.name = name;
this.age = age;
System.out.println("Person5构造器");
}
public void info() {
System.out.println("我叫" + name + ",我今年" + age + "岁了");
}
}
class Student5 extends Person5 {
//学号
int sno;
public Student5(String name, int age, int sno) {
//调用父类的有参构造器,对name和age进行赋值
super(name, age);
this.sno = sno;
System.out.println("Student构造器");
}
public void study() {
System.out.println("好好学习,天天向上");
}
}
public class Day1263 {
public static void main(String[] args) {
Student5 s1 = new Student5("张三", 30, 20191101); //创建两个对象,父类对象和子类对象
System.out.println(s1.name);
System.out.println(s1.age);
System.out.println(s1.sno);
Student5 s2 = new Student5("李四", 10, 20191102); //创建两个对象,父类对象和子类对象
System.out.println(s2.name);
System.out.println(s2.age);
System.out.println(s2.sno);
//一共四个对象
}
}
6.继承的规则一
静态成员(静态变量,静态常量,静态方法)不考虑继承问题,静态成员不能被继承。
子类不能继承父类的private 成员(属性和方法)。
protected成员包括包访问权限,protected成员可以被同一个包下的所有类访问。
protected成员可以被子类访问,不管这个子类和父类是否在同一个包下。
子类可以继承对它可见的成员。
子类可以继承父类的public,protected成员。
如果子类和父类在同一个包下,子类还可以继承父类的default成员。
构造器不是类的成员,因此无法被继承,但是子类可以使用super关键字调用其超类的构造器。 子类可以声明和超类同名的字段,这将导致隐藏其超类的字段。
class Person6 {
String name;
public Person6(String name) {
super();
this.name = name;
}
}
class Student6 extends Person6{
//子类的将隐藏超类的同名字段
private String name;
private int sno;
public Student6(String name1, String name2, int sno) {
super(name1);
//访问的是子类的name
name = name2;
this.sno = sno;
}
public void showInfo() {
//super代表父类的对象
System.out.println("父类对象的名字:" + super.name);
System.out.println("子类对象的名字:" + this.name);
//访问的是子类的name
System.out.println("我的名字:" + name + "我的学号" + sno);
}
}
public class Day127 {
public static void main(String[] args) {
Student6 s = new Student6("1", "2", 20191101);
s.showInfo(); //父类对象的名字:1
//子类对象的名字:2
//我的名字:2我的学号20191101
}
}
7.练习
1,编写一个Person类,包括属性(name、age),有参构造器、方法say(返回自我介绍的字符串)。
2.编写一个 Student类,继承Person类,增加sno、score属性,以及有参构造器,在子类中调用父类的构造器。
3.编写一个方法showInfo(返回自我介绍的字符串)。