包(package):其实就是存放类的文件夹,一般命名为(例子:com.baidu.demo1),其目的是为了把不同的类区分开来,以免文件名冲突带来不必要的麻烦,导包一般使用import(例子:import java.util.Date),或者使用某个方法时IDEA会自动导包。
面向对象编程语言第二大特性:继承( 被继承的类,我们称为 父类/基类/超类。而继承自其他类的新类,我们称为 子类/派生类。class A extends B(其中A为子类,B为父类)【为了代码的复用,不要有冗余的代码】
继承表示 is - a 语义, 猫 "是" 一种动物
class Animal {
public Animal(String name) {
this.name = name;
}
}
class Cat extends Animal {
public Cat(String name) {
// 使用 super 调用父类的构造方法.
super(name);
}
子类会继承父类的属性(成员变量)和方法(除构造方法,构造方法存在的意义就是为了帮助类去创建对象,因此可以带参数或者不带参数,如果不写构造方法那么系统会默认生成一个不带参数的构造方法)
子类构造首先需要构造父类,调用父类的构造方法,帮助父类进行构造;
1.super.func() 调用父类的方法
2.super.data 调用父类的属性
3.super() 调用父类的构造方法[必须放在第一行]
Java 中对于字段和方法共有四种访问权限:
- private:类内部能访问, 类的外部不能访问;
- 默认/default: 类内部能访问, 同一个包中的类可以访问, 其他类不能访问;
- protected: 类内部能访问, 子类和同一个包中的类可以访问, 其他类不能访问;
- public:类内部和类的调用者都能访问。
我们希望类要尽量做到 "封装",即隐藏内部实现细节, 只暴露出必要的信息给类的调用者。因此我们在使用的时候应该尽可能的使用 比较严格 的访问权限,例如如果一个方法能用 private,就尽量不要用 public 。
final 关键字,修饰一个变量或者字段的时候,表示 该值为常量 (不能修改);final也能修饰类,表示被修饰的类就不能被继承。
我们平时使用的 String 字符串类, 它的源码是用 final 修饰的,表示为最终类,不能再被继承。
组合表示 has - a 语义, 学校 "包含/有" 学生和教师
public class Student {
...
}
public class Teacher {
...
}
public class School {
public Student[] students;
public Teacher[] teachers;
}
面向对象编程语言第三大特性:多态(1.向上转型-->2.方法重写-->3.动态绑定)
什么是多态?
字面理解:同一对象的不同形态;
程序分析:父类(或接口)的引用指向子类(或具体实现类)的对象,且两者间有同名的重写方法,此时如果通过父类引用来调用这个方法的时候,会发生动态绑定,从而调用子类中的该方法,这个过程就叫做运行时多态,简称多态。
1.向上转型
一个父类 (Animal) 的引用,指向一个子类 (Bird) 的对象,这种写法称为 向上转型。
Animal bird = new Bird("豆豆");
为啥叫 "向上转型" ?
在面向对象程序设计中,针对一些复杂的场景(很多类,很复杂的继承关系),程序员会首先画UML 图的方式来整理清楚类之间的关系。此时父类通常画在子类的上方,所以我们就称为 "向上转型" ,表示往父类的方向转。
2.方法重写
方法名、参数个数和类型、返回值完全相同,只能用在继承关系当中,父类的方法只能被子类重写一次,权限 >= 父类,这样的两个方法构成重写。
public class Animal {
(default) void eat(String food) {
...
}
}
public class Bird extends Animal {
@Override
public void eat(String food) {
...
}
}
重载和重写(private和static修饰的方法不支持重写):
相同点:
(1)要求方法名相同;
(2)都可以用于抽象方法和非抽象方法之间。不同点:
(1)重写要求参数必须相同;而方法的重载要求参数签名必须不同。
(2)重写要求返回类型必须相同;而方法重载对此没有限制。
(3)重写只能用于子类重写父类的方法;而方法的重载用于同一个类的所有方法(包括从父类中继承的方法)。
(4)重写对方法的访问权限和抛出的异常有特殊要求;而方法的重载对此没有任何限制。
(5)父类的一个方法只能被子类重写一次;而一个方法在所在的类中可以被多次重载。
3.动态绑定
调用类中的某个方法时,实际执行了哪段代码 (是父类方法的代码还是子类方法的代码) , 要看究竟这个引用指向的是父类对象还是子类对象。这个过程是程序运行时决定的(而不是编译期),因此称为 动态绑定。
Animal animal1 = new Animal("豆豆");
animal1.eat("谷子");
Animal animal2 = new Bird("扁扁");
animal2.eat("谷子");
多态代码示例:
//画画(父类)
class Shape {
public void draw() {
}
}
//画圆形(子类)
class Cycle extends Shape {
@Override
public void draw() {
System.out.println("○");
}
}
//画方块(子类)
class Rect extends Shape {
@Override
public void draw() {
System.out.println("□");
}
}
//画花型(子类)
class Flower extends Shape {
@Override
public void draw() {
System.out.println("♣");
}
}
// Test.java (测试类)
public class Test {
public static void main(String[] args) {
Shape shape1 = new Flower();
Shape shape2 = new Cycle();
Shape shape3 = new Rect();
drawMap(shape1);
drawMap(shape2);
drawMap(shape3);
}
// 打印单个图形
public static void drawShape(Shape shape) {
shape.draw();
}
}
使用多态的好处是什么?
1) 多态是封装的更进一步:封装是让类的调用者不需要知道类的实现细节;多态让类的调用者连这个类的类型是什么都不必知道。
2) 能够降低代码的 "圈复杂度",避免使用大量的 if - else使得代码难以阅读。
3) 可扩展能力更强,如果要新增一种新类,使用多态的方式代码改动成本也比较低(对于类的调用者来说,只要创建一个新类的对象就可以了, 改动成本非常低。而对于不用多态的情况,就要对 if - else 进行一定的修改,改动成本非常高。
向下转型:
向下转型(使用的不多)
Animal animal = new Cat("小猫");
if (animal instanceof Bird) {
Bird bird = (Bird)animal;
bird.fly();
}
instanceof 可以判定一个引用是否是某个类创建的对象。
super与this的区别:
super 表示 由子类访问父类的属性或方法;
this 表示 访问本类中的属性或方法