关于OOP语言的基础

面向对象编程

包 继承 组合 多态 抽象类 接口

包 (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).
关于重写的注意事项

  1. 重写和重载完全不一样. 不要混淆(思考一下, 重载的规则是啥?)
  2. 普通方法可以重写, static 修饰的静态方法不能重写.
  3. 重写中子类的方法的访问权限不能低于父类的方法访问权限.
  4. 重写的方法返回值类型不一定和父类的方法相同(但是建议最好写成相同, 特殊情况除外.

多态实例

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对应的实例相关),这种行为就成为多态.

多态的好处:

  1. 类调用者对类的使用成本进一步降低.
    封装是让类的调用者不需要知道类的实现细节.
    多态能让类的调用者连这个类的类型是什么都不必知道,只需要知道这个对象具有某个方法即可
    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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值