Java面向对象

面向对象 OOP

  • object-oriented programming

  • java编程核心思想就是面向对象

  • 面向对象三大特性
    ①封装 | ②继承 | ③多态

  • 对于描述复杂的事物,为了从宏观上把握、 从整体上合理分析,我们需要使用面向对象的思路来分析整个系统。但是,具体到微观操作,仍然需要面向过程的思路去处理。


什么是面向对象

  • 面向对象的本质:以类的方式组织代码,以对象的方式组织(封装)数据。
  • 抽象
  • 三大特性:封装+继承+多态
  • 类是对象的模板、抽象;对象是类的具体实例
package com.ylq;

public class Demo01 {
    public static void main(String[] args) {
        System.out.print(whoMax(99,97));
    }
    public static int whoMax(int x, int y){
        return x>y? x:y;
    }
//    修饰符 返回值类型 方法名(参数列表){
//        方法体
//        return [返回值];
//    }
}

  • break: ①跳出switch ②跳出循环
  • continue:跳出一次循环
  • return: 方法结束

  • static修饰符
    1 可以支持起 类.方法 的调用,不然的话得 对象.方法 来调用。
    2 static加载的时间很早,和类一起加载。没有static的要在类实例化以后才加载。
package com.ylq;

public class Demo02 {
    public static void main(String[] args) {
        Archer shiLang = new Archer();
        shiLang.selfIntroduction();
        shiLang.setNew(shiLang,1,"卫宫士郎");
        shiLang.selfIntroduction();
    }
}

class Archer {
    int id = 0;
    String name = "吉尔伽美什";

    public static void setNew(Archer newOne,int id,String name) {
        newOne.id = id;
        newOne.name = name;
    }

    public void selfIntroduction() {
        System.out.println("I\'m an Archer,"+name+",ID"+id);    }
}

上例中因为传递的参数是一个对象,故属于引用传递。方法内部的赋值行为会影响方法外部。

类与对象的创建

tips:

一个程序最好只有一个main方法,是程序的入口
一般会创建一个主启动类Application,在这个类中写main方法


类的构造器

一个类即使什么都不写也会自动生成一个构造方法,如如上例中的

Archer()

构造方法也可以显示地定义:

  • 必须与类同名,而且不能写返回值类型(void也不能写)
  • 显示定义可以用来初始化一些信息
  • 可以无参构造也可以有参构造
  • new关键字本质是调用构造器
  • 定义有参构造的时候必须显示地定义一个无参构造
  • intelij IDEA用快捷键alt+insert可以快速创建构造器
package com.ylq.demo03;

public class Ninja {
    int id;
    String name;

    public Ninja() {
        this.id = 0;
        this.name = "小胖";
    }
    public Ninja(int fpID,String fpName){
        this.id = fpID;
        this.name = fpName;
    };

    public void selfIntroduce() {
        System.out.println("我是"+this.name+",NO."+this.id+".");

    }
}
package com.ylq.demo03;

public class Application {
    public static void main(String[] args) {
        Ninja xiaoPang = new Ninja();
        xiaoPang.selfIntroduce();
        Ninja longMa = new Ninja(1,"龙马");
        longMa.selfIntroduce();
    }
}

Java内存分析


面向对象三大特性


封装

  • 高内聚,低耦合
  • 高内聚:类的内部数据操作细节自己完成,不允许外部干涉。
  • 低耦合:尽量暴露少量的方法给外部使用。
  • 数据的隐藏:通常,应禁止直接访问一个对象中的·实际表示,而应通过操作接口来访问。
  • 属性私有private,get/set
  • set方法中经常会做一些安全性验证。
  • 封装的意义:

1.提高程序的安全性,保护数据
2.隐藏代码的实现细节
3.统一接口
4.系统可维护性增加了


继承

  • 继承的本质是对某一批类的抽象,从而实现对现实世界更好的建模。

  • extends的意思是“扩展”。子类是父类的扩展。

  • JAVA中的类只有单继承,没有多继承!

  • 继承是类和类之间的一种关系。除此之外,类和类之间的关系还有依赖、组合、聚合等。

  • 继承关系的两个类,一个为子类(派生类),一个为父类(基类)。子类继承父类,使用关键字extends来表示。

  • 子类和父类之间,从意义上讲应该具有“is a”的关系。

  • object类

  • super

  • 方法重写

  • ctrl+h可以查看继承树

package com.ylq.demo05;

public class Spirit {
    private int id;
    private String name;

    public Spirit() {
    }

    public Spirit(int id, String name) {
        this.id = id;
        this.name = name;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
package com.ylq.demo05;

public class Rider extends Spirit {
    private String mountName;

    public Rider() {
    }

    public Rider(int id, String name) {
        super(id, name);
    }

    public Rider(String mountName) {
        this.mountName = mountName;
    }

    public Rider(int id, String name, String mountName) {
        super(id, name);
        this.mountName = mountName;
    }

    public String getMountName() {
        return mountName;
    }

    public void setMountName(String mountName) {
        this.mountName = mountName;
    }

    public void selfIntroduce(){
        System.out.println("我是Rider,真名"+this.getName()+",ID"+this.getId()+",我的坐骑是"+getMountName()+".");
    }
}

package com.ylq.demo05;

public class Application {
    public static void main(String[] args) {
        Rider medusa = new Rider(1,"美杜莎","小白马");
        medusa.selfIntroduce();

    }
}


  • Java中所有的类都默认直接或间接继承Object类

  • 调用子类的无参构造的时候默认隐式调用父类无参构造

  • 想显示调用父类构造器super()必须放在第一行

  • 构造器中调用本对象的构造器this()也必须放在第一行

  • 故上面两个构造器调用只能用一个

super

和this一样都是代词。super可以指代父类对象,甚至可以指代父类构造函数。

方法重写
  • 需要有继承关系,子类重写父类的方法!
  1. 方法名必须相同
  2. 参数列表必须相同
  3. 修饰符:范围可以扩大但不能缩小 public > protected > default > private
  4. 抛出的异常:范围可以缩小但不能扩大 ClassNotFoundException --> Exception

下例中的非静态写法就是方法的重写

package com.ylq.demo06;

public class Father {
    public static void test() {
        System.out.println("测试了父类");
    }
    public void testWithoutStatic() {
        System.out.println("测试了父类withoutStatic");
    }
}
package com.ylq.demo06;

public class Son extends Father {
    public static void test() {
        System.out.println("测试了子类");
    }
    public void testWithoutStatic() {
        System.out.println("测试了子类withoutStatic");
    }
}

package com.ylq.demo06;

public class Application {
    public static void main(String[] args) {
        Son pang = new Son();
        pang.test();
        
        //静态方法:
        //分别调用Father和Son的test
        //方法的调用只和左边定义的数据类型有关系
        //父类的引用指向子类
        Father shou = new Son();
        shou.test();
        
        //非静态方法:
        //都是调用Son的test
        //方法的调用只和构造函数的引用有关
        //子类重写了父类的方法
        pang.testWithoutStatic();
        shou.testWithoutStatic();
        
        //结果:
        //测试了子类
       // 测试了父类
        //测试了子类withoutStatic
       // 测试了子类withoutStatic
    }
}

不能重写的情况

  • static 方法属于类,不属于实例

  • final 常量

  • private 私有的方法

修饰符public \ protected \ default \ private
类内部 本包 子类 外部包
public
protected ×
default × ×
private × × ×

多态

  • 即同一方法可以根据发送对象的不同而采用多种不同的行为方式。
  • 一个对象的实际类型是确定的,但可以指向对象的引用类型有很多(一般是父类或有关系的类)
  • 多态存在的条件
  • 有继承关系
  • 子类重写父类方法
  • 父类引用指向子类对象
  • 注意: 多态是方法的多态,属性没有多态(同重写)
  • instanceof 引用类型间的类型转换,测试某对象是否属于特定类

package com.ylq.demo07;

public class Application {
    public static void main(String[] args) {
        Object naMei = new Navigator();
        System.out.print((naMei instanceof Navigator)+" | ");   //  √
        System.out.print((naMei instanceof Pirate)+" | ");   //  √
        System.out.print((naMei instanceof Object)+" | ");   //  √
        System.out.print((naMei instanceof Captain)+" | ");   //  ×
        System.out.print((naMei instanceof Warrior)+" | ");   //  ×
        System.out.print((naMei instanceof String)+" | \n");   //  ×
        System.out.println("---------------------------------------");

        Pirate luFei = new Captain();
        System.out.print((luFei instanceof Navigator)+" | ");   //  ×
        System.out.print((luFei instanceof Pirate)+" | ");   //  √
        System.out.print((luFei instanceof Object)+" | ");   //  √
        System.out.print((luFei instanceof Captain)+" | ");   //  √
        System.out.print((luFei instanceof Warrior)+" | ");   //  ×
        //System.out.print((luFei instanceof String)+" | \n");   编译时报错
        System.out.println("---------------------------------------");

        Warrior zoro = new Warrior();
        //System.out.print((zoro instanceof Navigator)+" | ");   编译时报错
        System.out.print((zoro instanceof Pirate)+" | ");   //  √
        System.out.print((zoro instanceof Object)+" | ");   //  √
        //System.out.print((zoro instanceof Captain)+" | ");   编译时报错
        System.out.print((zoro instanceof Warrior)+" | ");   //  √
        //System.out.print((zoro instanceof String)+" | \n");   编译时报错
        System.out.println("---------------------------------------");
    }
}

  • 强制类型转换
  • 类型转换低转高,可以自动转换;高转低,需要强制类型转换
  • 引用型数据中:父类-高,子类-低
  • Object obj = String(); 左高右低,低转高,自动转换
  • 子类强转父类会丢失一些方法

多态小结:

  1. 父类的引用指向子类的对象
  2. 把子类转换为父类,向上转型
  3. 把父类转换为子类,向下转型,需要强制转换
  4. 方便方法的调用,减少重复的代码!简洁

Static详解

  • static的属性和方法属于类,不用实例化成对象就可以调用。

  • 静态属性不因对象变多而增加,一直就一个。

  • 静态方法在加载类的时候就加载了,存在堆得方法区中,可以直接 类.方法 调用

  • 静态代码块:只在加载类的时候执行一次,在构造函数之前

static{
    ...
}
package com.ylq.demo08;

import org.w3c.dom.ls.LSOutput;

public class CodeBlock {
    {
        System.out.println("匿名代码块");
    }
    static{
        System.out.println("静态代码块");
    }
    public CodeBlock() {
        System.out.println("构造函数");
    }

    public static void main(String[] args) {
        CodeBlock pang = new CodeBlock();
        System.out.println("-----------------------");
        CodeBlock shou = new CodeBlock();
    }
}

/*
静态代码块
匿名代码块
构造函数
-----------------------
匿名代码块
构造函数
 */
  • 静态导入包
import static java.lang.Math.random;

tips: final修饰的东西不能继承给子类,final修饰的类断子绝孙了

抽象类

  • abstract修饰符可以用来修饰方法也可以修饰类,→抽象方法、抽象类。
  • 抽象类中可以没有抽象方法,但抽象方法的类一定要声明为抽象类。
  • 抽象类,不能使用new关键字来创建对象,它是用来让子类实现的。
  • 子类继承抽象类,那么就必须要实现抽象类没有实现的抽象方法,否则该子类也要声明为抽象类。
package com.ylq.demo09;

public abstract class Mood {
    protected abstract void influence();
}

抽象类中的抽象方法可以只有名字,没有具体实现的代码

package com.ylq.demo09;

public class Happy extends Mood {
    @Override
    protected void influence() {
        System.out.println("心情越快,乐观向上");
    }
}

抽象类有局限性,因为继承的单继承特性。但是通过接口可以实现多继承。
故实际开发中接口用得比较多。

接口

  • 普通类:只有具体实现。

  • 抽象类:具体实现和规范(抽象方法)都有!

  • 接口:只有规范,自己无法写方法。体现了约束和实现分离。

  • 接口就是规范,定义的是一组规则,体现了现实世界中“如果你是。。则必须能。。”的思想。如果你是坏人,则必须欺负好人。

  • 接口的本质是契约,就像我们人间的法律一样。制定好后大家都遵守。

  • OO的精髓,是对对象的抽象,最能体现这一点的就是接口。为什么我们讨论设计模式都只针对具备了抽象能力的语言(比如C++、Java、C#等),就是因为设计模式所研究的,实际上就是如何合理的去抽象

  • 声明类的关键字是class,声明接口的关键字是interface

  • 接口中的方法默认都是public abstract

  • 接口的实现类一般以impl结尾(implement使实现)

  • 接口中定义的属性都默认为常量,省略了public static final

package com.ylq.demo10;

public interface UserService {
    int AGE = 20;
    void add();
    void delete();
    void update();
    void query();
}
package com.ylq.demo10;

public interface TimeService {
    void setTime();
}
package com.ylq.demo10;

public class UserServiceImpl implements UserService,TimeService{
    @Override
    public void setTime() {
    }

    @Override
    public void add() {
    }

    @Override
    public void delete() {
    }

    @Override
    public void update() {
    }

    @Override
    public void query() {
    }
}

内部类

  • 内部类就是在一个类的内部再定义一个类。
  • 非静态内部类可以调用外部类的私有属性
  • 静态内部类不能调用非静态外部类的私有属性

1.成员内部类
2.静态内部类
3.局部内部类 (比如在方法内写的类)
4.匿名内部类 (new Allpe.eat();没有把创建的对象指向任何引用名,直接用)

package com.ylq.demo11;

public class Outer {
    private int id = 10;
    public class Inner {
        protected void letsGo(){
            System.out.println("内部类起飞,还能输出外部类私有属性:"+id);
        }
    }
}
package com.ylq.demo11;

public class Application {
    public static void main(String[] args) {
        Outer littleBoy = new Outer();
        Outer.Inner devil = littleBoy.new Inner();
        devil.letsGo();
    }
}
posted @ 2021-02-14 13:20  菜鸟巫师illich  阅读(22)  评论(0编辑  收藏  举报