面向对象编程
包 继承 组合 多态 抽象类 接口
包
包 (package) 是组织类的一种方式;使用包的主要目的是保证类的唯一性
创建一个包
找到工程文档下的src文件,右键单击 ,选择new-> package ,输入包名完成创建
注意:包的名字必须小写
导入包中的类
impor java.util.* 或者 import java.util.+包的类名
eg: import java.util.; import java.util.Date;
import java.sql.;
import java.util.Arrays;
import java.util.Date;
静态导入
使用import static 可以导入包中的静态方法和字段
eg:import static java.lang.Math.*;
将类放到包里
选中创建好的包的文件名右键单击选择new ->java classs 输入类名进行创建
常见的系统包
1.java.lang;系统常用基础类(String、Object),此包从JDK1.1后自动导入
2.java.lang.relect:java反射编程包;
3.java.net :进行网络编程开发包;
4.java.sql :进行数据开发的支持包;
5.java.util :设计java提供的工具支持包;
6.java.I/O :I/O编程开发包。
继承
背景
代码中创建的类, 主要是为了抽象现实中的一些事物(包含属性和方法).
有的时候客观事物之间就存在一些关联关系, 那么在表示成类和对象的时候也会存在一定的关联.
class Animal {
protected String name;
public Animal(String name){
this.name = name;
}
}
class Cat{
public String name;
public Cat(String name) {
this.name = name;
}
public void eat(String food) {
System.out.println(this.name + "正在吃" + food);
}
}
class Bird{
public String name;
public Bird(String name) {
this.name = name;
}
public void eat(String food) {
System.out.println(this.name + "正在吃" + food);
}
}
class Duck{
public String name;
public Duck(String name) {
this.name = name;
}
public void eat(String food) {
System.out.println(this.name + "正在吃" + food);
}
}
这个代码我们发现其中存在了大量的冗余代码.
Animal 和 Cat 、Bird以及 Bird 这几个类中存在一定的关联关系:
这三个类都具备一个相同的 eat 方法, 而且行为是完全一样的,这三个类都具备一个相同的 name 属性, 而且意义是完全一样的,从逻辑上讲, Cat 和 Bird 都是一种 Animal (is - a 语义);此时我们就可以让 Cat 和 Bird 分别继承 Animal 类, 来达到代码重用的效果.,此时, Animal 这样被继承的类, 我们称为父类 , 基类或超类, 对于像 Cat 和 Bird 这样的类, 我们称为子类, 派生类,和现实中的儿子继承父亲的财产类似, 子类也会继承父类的字段
class 子类 extens 父类
1.使用 extends 指定父类.
2.Java 中一个子类只能继承一个父类 .
3.子类会继承父类的所有 public 的字段和方法.
4对于父类的 private 的字段和方法, 子类中是无法访问的.但是可以继承
5.子类的实例中, 也包含着父类的实例,可以使用super关键字得到父类实例的引用
对于上述代码可写为:
class Animal {
protected String name;
public Animal(String name){
this.name = name;
}
}
class Cat{
public Cat(String name) {
super(name);
}
public void eat(String food) {
System.out.println(this.name + "正在吃" + food);
}
}
class Bird{
public Bird(String name) {
super(name);
}
public void eat(String food) {
System.out.println(this.name + "正在吃" + food);
}
}
class Duck{
public Duck(String name) {
super(name); //使用super调用父类的构造方法
}
public void eat(String food) {
System.out.println(this.name + "正在吃" + food);
}
}
prorected关键字
1.对于类的调用者来说, protected 修饰的字段和方法是不能访问的
2.对于类的子类和同一个包的其他类 来说, protected 修饰的字段和方法是可以访问的
public class Animal {
protected String name;
public Animal(String name) {
this.name = name;
}
public void eat(String food) {
System.out.println(this.name + "正在吃" + food);
}
}
小结: Java 中对于字段和方法共有四种访问权限
private: 类内部能访问, 类外部不能访问
默认(也叫包访问权限): 类内部能访问, 同一个包中的类可以访问, 其他类不能访问.
protected: 类内部能访问, 子类和同一个包中的类可以访问, 其他类不能访问.
public:类内部和类的调用者都能访问
final关键字
曾经我们学习过 final 关键字, 修饰一个变量或者字段的时候, 表示 常量 (不能修改).
final int a = 10;
a = 20;//编译出错
final 关键字也能修饰类, 此时表示被修饰的类就不能被继承.
final 关键字的功能是限制类被继承
“限制” 这件事情意味着 “不灵活”. 在编程中, 灵活往往不见得是一件好事. 灵活可能意味着更容易出错.
用 final 修饰的类被继承的时候, 就会编译报错, 此时就可以提示我们这样的继承是有悖这个类设计的初衷的.
super 关键字
1.由子类访问父类中的属性、方法
2.不查找本类而直接调用父类定义
组合
和继承类似, 组合也是一种表达类之间关系的方式, 也是能够达到代码重用的效果.
组合表示 has - a 语义
继承表示 is - a 语义
多态
向上转型
父类的引用指向子类的实例
向上转型发生的时机:
直接赋值
public static void main4(String[] args) {
Animal bird = new Bird("PANPAN");//发生向上转型 父类的引用 引用子类的引用
bird.eat();// 直接赋值
Bird bird1 = new Bird("圆圆");
}
方法传参
public class Test {
public static void main(String[] args) {
Bird bird = new Bird("圆圆");
feed(bird);
}
public static void feed(Animal animal) {
animal.eat("谷子");
}
}
方法返回
public class Test {
public static void main(String[] args) {
Animal animal = findMyAnimal();
}
public static Animal findMyAnimal() { //定义一个返回类型为Animal类型的引用
Bird bird = new Bird("圆圆");
return bird;
}
}
动态绑定
父类和子类出现同名的方法,去调用这个该方法时会发生东动态绑定
class Animal {
protected String name ;
public Animal(String name) {
this.name = name;
}
public void eat(){
System.out.println(this.name+"正在吃....");
}
}
class Bird extends Animal{
public Bird(String name) {
//使用super调用父类的构造方法
super(name);//带参的构造方法
}
@Override
public void eat(){
super.eat();
System.out.println(this.name+"正在吃....!!!");
}
public void fly(){
System.out.println(this.name+"正在飞︿( ̄︶ ̄)︿....");
}
}
public class Tset {
public static void main(String[] args) {
Animal animal = new Animal("PANPAN");
animal.eat();
Animal bird = new Bird("PANPAN1");
bird.eat();
Animal animal1 = new Bird("panpan");
animal1.eat();
}
}
运行结果为:
PANPAN正在吃…
PANPAN1正在吃…
PANPAN1正在吃…!!!
panpan正在吃…
panpan正在吃…!!!
animal 和 animal1 虽然都是 Animal 类型的引用, 但是 animal 指向 Animal 类型的实例, animal21指向Bird 类型的实例.
针对 animal 和 animal1 分别调用 eat 方法, 发现 animal.eat() 实际调用了父类的方法, 而animal1.eat()实际调用了子类的方法
在 Java 中, 调用某个类的方法, 究竟执行了哪段代码 (是父类方法的代码还是子类方法的代码) , 要看究竟这个引用指向的是父类对象还是子类对象. 这个过程是程序运行时决定的(而不是编译期), 因此称为 动态绑定.
方法重写
针对刚才的 eat 方法来说:
@Override
public void eat(){
super.eat();
System.out.println(this.name+"正在吃....!!!");
}
子类实现父类的同名方法, 并且参数的类型和个数完全相同, 这种情况称为 覆写/重写/覆盖(Override).
关于重写的注意事项
- 重写和重载完全不一样. 不要混淆(思考一下, 重载的规则是啥?)
- 普通方法可以重写, static 修饰的静态方法不能重写.
- 重写中子类的方法的访问权限不能低于父类的方法访问权限.
- 重写的方法返回值类型不一定和父类的方法相同(但是建议最好写成相同, 特殊情况除外.
多态实例
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("❀");
}
}
class Triangle extends Shape {
@Override
public void draw() {
System.out.println("△");
}
}
"================================================"
public class Test2 {
public static void drawMap (Shape shape){
shape.draw();
}
public static void main(String[] args) {
Shape shape = new Cycle();
Shape shape1 = new Rect();
Shape shape2 = new Flower();
drawMap(shape);
drawMap(shape1);
drawMap(shape2);
}
}
在这个代码中, 分割线上方的代码是 类的实现者 编写的, 分割线下方的代码是 类的调用者 编写的.
当类的调用者在编写 drawMap 这个方法的时候, 参数类型为 Shape (父类), 此时在该方法内部并不知道, 也不关注当
前的 shape 引用指向的是哪个类型(哪个子类)的实例. 此时 shape 这个引用调用 draw 方法可能会有多种不同的表现
(和 shape对应的实例相关),这种行为就成为多态.
多态的好处:
- 类调用者对类的使用成本进一步降低.
封装是让类的调用者不需要知道类的实现细节.
多态能让类的调用者连这个类的类型是什么都不必知道,只需要知道这个对象具有某个方法即可
2)能够降低代码的 “圈复杂度”, 避免使用大量的 if - else
3)可扩展能力更强
抽象类
在一个类中,没有实际工作的方法,我们可以设计成一个抽象方法,包含抽此昂方法的类叫做抽象类
abstract class Shape {
abstract public void draw();
}
在 draw 方法前加上 abstract 关键字, 表示这是一个抽象方法. 同时抽象方法没有方法体(没有 { }, 不能执行具体代码).
对于包含抽象方法的类, 必须加上 abstract 关键字表示这是一个抽象类.
abstract class Shape {
abstract public void draw();
void func() {
System.out.println("func()");
}
}
class Rect extends Shape {
@Override
public void draw() {
}
}
interface Ishape {
abstract void draw();
public static final int num = 10;//静态常量
}
class Cycle implements Ishape{
@Override
public void draw() {
System.out.println("○");
}
}
public class Test {
public static void main(String[] args) {
Ishape shape = new Cycle();
shape.draw();
}
public static void main1(String[] args) {
Shape shape = new Rect();
shape.func();
}
}
注意事项
1、包含抽象方法的类,抽象类。使用abstract关键字来修饰的
2、抽象方法是不能够有具体的实现的。
3、在抽象类当中,可以定义和普通类相同的数据属性和方法
4、抽象类不能够进行实例化.
Shape shape = new Shape();
5、抽象类天生就是为了被继承
6、一个普通类继承了这个抽象类之后,一定要重写,抽象类的抽象方法
7、如果一个类,继承了抽象类但是又不想重写这个抽象方法 那么就把这个类也设置为抽象类,但是迟早都要重写的。
8、抽象方法不能是private
作用
被继承
抽象类本身不能被实例化, 要想使用, 只能创建该抽象类的子类. 然后让子类重写抽象类中的抽象方法.
接口
接口是抽象类的更进一步. 抽象类中还可以包含非抽象方法, 和字段. 而接口中包含的方法都是抽象方法, 字段只能包含
静态常量.
class Animal {
protected String name;
public Animal(String name){
this.name = name ;
}
}
interface IFlying {
void fly();
}
interface IRunning {
void run();
}
interface ISwimming {
void swim();
}
class Cat extends Animal implements IRunning {
public Cat(String name) {
super(name);
}
@Override
public void run() {
System.out.println(this.name+ "正在跑......");
}
}
class Fish extends Animal implements ISwimming {
public Fish(String name) {
super(name);
}
@Override
public void swim() {
System.out.println(this.name + "正在用尾巴游泳");
}
}
class Frog extends Animal implements IRunning, ISwimming {
public Frog(String name) {
super(name);
}
@Override
public void run() {
System.out.println(this.name + "正在往前跳");
}
@Override
public void swim() {
System.out.println(this.name + "正在蹬腿游泳");
}
}
class Duck extends Animal implements IRunning, ISwimming, IFlying {
public Duck(String name) {
super(name);
}
@Override
public void fly() {
System.out.println(this.name + "正在用翅膀飞");
}
@Override
public void run() {
System.out.println(this.name + "正在用两条腿跑");
}
@Override
public void swim() {
System.out.println(this.name + "正在漂在水上");
}
}
class Robot implements IRunning {
@Override
public void run() {
System.out.println("机器人在跑.........");
}
}
1、接口当中的方法,一定是不能够有具体的实现的
2、接口当中default中修饰的方法才能够有具体的实现的。
3、接口当中的成员变量 都是public static final的
4、接口当中的方法都是public abstract
5、接口不能够进行实例化:Shape shape = new Shape();
6、接口也可以发生向上转型和运行时绑定
两个意义:
1、实现多继承
2、可扩展性非常强
接口实际上是对某一种功能或者行为的抽象
注意:
1、类和接口之间的关系 implements
抽象类可以实现接口
2、接口和接口之间的关系 extends