1 面向对象进阶
1.1 继承
1. 继承的概念
多个类中存在相同属性和行为时,将这些内容抽取到单独一个类中,那么多个类无需再定义这些属性和行为,只要继承那个类即可。
- 此处的多个类称为子类(派生类),单独的这个类称为父类(基类或超类)。可以理解为:“子类 is a 父 类”
- 子类继承了父类,就继承了父类的方法和属性。
- 在子类中,可以使用父类中定义的方法和属性,也可以创建新的数据和方法。
- 在Java中,继承的关键字用的是“extends”,即子类不是父类的子集,而是对父类的“扩展”。
- 类继承语法规则: class Subclass extends SuperClass{ }
- 类不能直接访问父类中私有的(private)的成员变量和方法。
- Java只支持单继承和多层继承,不允许多重继承
- class SubDemo extends Demo{ } //ok
- class SubDemo extendsDemo1,Demo2…//error
2. 练习
代码如下:
Creature:
public class Creature {
public void breath() {
System.out.println("生物呼吸");
}
}
Person:
public class Person extends Creature {
private String name;
private int age;
public void eat() {
System.out.println(name + "人在吃饭");
}
public void sleep() {
System.out.println(name + "人在睡觉");
}
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;
}
}
Student:
public class Student extends Person {
private String major;
public Student() {
}
public Student(String major) {
this.major = major;
}
//重写,子类的方法和父类的方法声明一致
//-方法名
//-参数
//-返回值
public void eat() {
System.out.println(getName() + "学员在吃饭");
}
public void sleep() {
System.out.println(getName() + "学员在睡觉");
}
public String getMajor() {
return major;
}
public void setMajor(String major) {
this.major = major;
}
public void show() {
System.out.println("name=" + super.getName() + " aget=" + super.getAge() + " major=" + major);
}
public void study() {
show();
System.out.println("学员在学习");
}
}
Test:
public class Test {
public static void main(String[] args) {
Creature c = new Creature();
c.breath();
System.out.println("----------");
Person p = new Person();
p.breath();
p.setName("张三");
p.setAge(21);
p.eat();
p.sleep();
System.out.println("----------");
Student s = new Student("Java");
s.breath();
s.setName("李四");
s.setAge(25);
s.eat();
s.sleep();
s.show();
s.study();
}
}
1.2 重写
在子类中可以根据需要对从父类中继承来的方法进行改造, 也称为方法的重置、覆盖override/overwrite。在程序执行时,子类的方法将覆盖父类的方法。
-
子类重写的方法必须和父类被重写的方法具有相同的方法名称、 参数列表
-
子类重写的方法的返回值类型不能大于父类被重写的方法的返回值类型
-
子类重写的方法使用的访问权限不能小于父类被重写的方法的访问权限
- 子类不能重写父类中声明为private权限的方法
-
子类方法抛出的异常不能大于父类被重写方法的异常
1.3 四种访问权限修饰符
Java权限修饰符public、protected、(缺省)、private置于类的成员定义前,用来限定对象对该类成员的访问权限。
对于class的权限修饰只可以用public和default(缺省)。
- public类可以在任意地方被访问。
- default类只可以被同一个包内部的类访问。
- private:当前类
- default:当前包可以访问
- protected:子类可以访问
- 在子类中new Parent().protected变量不能够访问
- 在子类中super.protected变量(方法)能够访问
- public:所有工程能够访问
演示案例:
目录结构
a包下创建
package f_modifier.a;
public class Parent {
private int b;
int a; //default
protected int c;
public int d;
private void f2() {
System.out.println("f2" + b);
}
void f1() {
System.out.println("f1");
}
protected void f3() {
System.out.println("f3");
}
public void f4() {
System.out.println("f4");
}
}
a和b包分别创建Children:
public class Children extends Parent {
public void f5() {
Parent p = new Parent();
//1. 不能访问私有变量
// new Parent().b; //报错
// new Parent().f2(); //报错,因为不能访问其他类的private
//2. default,不带修饰符,包内可以访问
System.out.println(p.a);
System.out.println(super.a);
p.f1();
//3.protected(类,包,子类)
System.out.println(p.c);
System.out.println(super.c);
f3();
//3.public(当前类,当前包,子类, 所有)
System.out.println(p.d);
System.out.println(super.d);
f4();
System.out.println("f5");
}
}
package f_modifier.b;
import f_modifier.a.Parent;
public class Children extends Parent {
public void f5() {
Parent p = new Parent();
//1.private (当前类)
// new Parent().b; //报错
// new Parent().f2(); //报错,因为不能访问其他类的private
//2. default,(当前类,当前包)
// System.out.println(p.a);
// System.out.println(super.a);
// p.f1();
//3.protected(类,包,子类)
// System.out.println(p.c); //不属于子类访问
System.out.println(super.c);
System.out.println(this.c);
this.f3();
//4.public(当前类,当前包,子类, 所有)
System.out.println(p.d);
System.out.println(super.d);
f4();
System.out.println("f5");
}
}
1.4 super关键词
- super可用于访问父类中定义的属性
- super可用于调用父类中定义的成员方法
- super可用于在子类构造器中调用父类的构造器
- super的追溯不仅限于直接父类
- super和this的用法相像, this代表本类对象的引用,super代表父类的内存空间的标识
1. 调用父类方法
public String getInfo() {
return super.getInfo() + "\nschool: " + school;
}
2. 调用父类构造函数
public Student(String name, int age, String s) {
super(name, age);
school = s;
}
this和super的区别
1.5 多态
案例:
Person:
public class Person {
protected String name;
protected int age;
public Person() {
}
public Person(String name) {
this.name = name;
}
public Person(String name, int age) {
//使用this调用构造函数
this(name);
// this.name = name;
this.age = age;
}
public void eat() {
System.out.println("人在吃饭");
}
public void sleep() {
System.out.println("人在睡觉");
}
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;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
Student:
public class Student extends Person {
private String major;
public Student() {
}
public Student(String name, int age, String major) {
super(name, age);
this.major = major;
}
public void eat() {
super.eat();
System.out.println(super.name + "学员在吃饭");
}
public void sleep() {
System.out.println(super.name + "学员在睡觉");
}
public String getMajor() {
return major;
}
public void setMajor(String major) {
this.major = major;
}
public void show() {
System.out.println("name=" + super.getName() + " aget=" + super.getAge() + " major=" + major);
}
public void study() {
show();
System.out.println("学员在学习");
}
@Override
public String toString() {
return "Student{" +
"name='" + this.getName() + '\'' +
"age='" + this.getAge() + '\'' +
"major='" + major + '\'' +
'}';
}
}
Test:
public class Test {
public static void main(String[] args) {
Person p1 = new Person("张三", 31);
System.out.println(p1);
System.out.println("----------------");
Student s1 = new Student("李四", 18, "java");
// s1.setName("高飞");
// s1.setAge(18);
System.out.println(s1);
s1.eat();
}
}
多态性:父类的引用指向子类的对象
案例:
- Animal
package h_multi;
public class Animal {
public void eat() {
System.out.println("动物吃饭");
}
public void shout() {
System.out.println("动物叫。。。");
}
}
Dog:
package h_multi;
public class Dog extends Animal {
@Override
public void eat() {
System.out.println("狗吃骨头....");
}
@Override
public void shout() {
System.out.println("狗在汪汪叫....");
}
}
- Cat:
package h_multi;
public class Cat extends Animal {
@Override
public void eat() {
System.out.println("猫吃鱼....");
}
@Override
public void shout() {
System.out.println("猫在喵喵叫....");
}
}
- 不用多态实现宠物训练
package h_multi;
public class Master {
//操作狗的行为(没有使用多态)
public void func(Dog dog) {
dog.eat();
dog.shout();
}
//操作猫的行为(没有使用多态)
public void func(Cat cat) {
cat.eat();
cat.shout();
}
//狮子,老虎
//...操作狮子的方法
//...操作老虎的方法
public static void main(String[] args) {
//里氏替换原则——>子类一定能够代替父类
Master master = new Master();
Dog dog = new Dog();
Cat cat = new Cat();
Tiger tiger = new Tiger();
master.func(dog);
master.func(cat);
master.func(tiger);
}
}
- 多态宠物训练实现
package h_multi;
public class Master {
//多态的实现版本
public void func(Animal animal) {
animal.eat();
animal.shout();
}
public static void main(String[] args) {
//里氏替换原则——>子类一定能够代替父类
Master master = new Master();
Dog dog = new Dog();
Cat cat = new Cat();
Tiger tiger = new Tiger();
master.func(dog);
master.func(cat);
master.func(tiger);
}
}
- 增加一个Tiger老虎类
package h_multi;
public class Tiger extends Animal {
@Override
public void eat() {
System.out.println("老虎吃人");
}
@Override
public void shout() {
System.out.println("老虎嗷嗷叫");
}
}
1. 多态分析
- 多态性,是面向对象中最重要的概念, 在Java中的体现:对象的多态性:父类的引用指向子类的对象
- Java引用变量有两个类型:编译时类型和运行时类型。 编译时类型由声明该变量时使用的类型决定, 运行时类型由实际赋给该变量的对象决定。 简称: 编译时,看左边;运行时, 看右边。
- 若编译时类型和运行时类型不一致, 就出现了对象的多态性(Polymorphism)
- 多态情况下, “看左边” : 看的是父类的引用(父类中不具备子类特有的方法)“看右边” :看的是子类的对象(实际运行的是子类重写父类的方法)
- 多态,提高了代码的通用性,常称作接口重用
2. instanceof关键词
判断对象是否属于一个类型,一般在强制类型转换前,进行判断
3.强制类型装换
对Java对象的强制类型转换称为造型
- 从子类到父类的类型转换可以自动进行
- 从父类到子类的类型转换必须通过造型(强制类型转换)实现
- 无继承关系的引用类型间的转换是非法的
- 在造型前可以使用instanceof操作符测试一个对象的类型
1.6 java.lang.Object对象
Object类是所有Java类的根父类 如果在类的声明中未使用extends关键字指明其父类, 则默认父类为java.lang.Object类
- ==:比较内存地址
- equals:比较内容,但是默认比较内存地址,源码如下:
- String因为重写了equels,所以String比较内容
public boolean equals(Object obj) {
return (this == obj);
}
- 重写equals
@Override
public boolean equals(Object obj) {
return this.age == ((Bean) obj).age;
}
- toString():打印时,会打印toString()方法
- 重写toString()方法,来自定义打印信息
@Override
public String toString() {
return "Bean{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
1.7 自动装箱和拆箱
- 装箱:基本数据类型包装成包装类的实例
- 通过包装类的构造器实现: int i = 500; Integer t = new Integer(i);
- 通过字符串参数构造包装类对象: Float f = new Float(“4.56”);
- 拆箱: 获得包装类对象中包装的基本类型变量,方式是调用包装类的.xxxValue()方法: boolean b = bObj.booleanValue();
- 自动装箱,自动拆箱:JDK1.5支持自动装箱和拆箱
字符串转换成基本数据类型
-
通过包装类的构造器实现: int i = new Integer(“12”);
-
通过包装类的parseXxx(String s)静态方法: Float f = Float.parseFloat(“12.1”);
-
基本数据类型转换成字符串
- 调用字符串重载的valueOf()方法: String fstr = String.valueOf(2.34f);
- 更直接的方式: String intStr = 5 + “”
-
装箱,基本数据类型转换成包装类,成为装箱
Integer i1 = 100;
int i = 123;
Integer i2 = new Integer(123);
Integer i3 = new Integer("456");
//基本数据类型int->对应的包装类->Integer
//float-> Float
- 拆箱:包装类转换成基本数据类型
Integer i1 = new Integer(123);
//拆箱
int i2 = i1.intValue();
Boolean b2 = new Boolean(false);
boolean b3 = b2.booleanValue(); //拆箱