Java学习笔记八: 面向对象下

私有化构造函数:

  1. 工具类(全都是静态方法或者静态属性)
  2. 单例模式

单例模式:

某类创建对象只能且最多只有一个对象

将构造函数用private修饰, 让外界无法创建对象

在特殊情况下, 不允许外界创建对象, 减少堆内存占用

步骤:

  1. 私有化构造函数, 杜绝外界创建对象
  2. 内部创建该类对象(静态)
  3. 提供公共接口向外提供该类的对象

饿汉式:

提前提供一个对象

缺点: 即便没有使用对象, 也从始至终常驻内存, 浪费内存

public class Singleton {
  private static Singleton singleton = new Singleton;
  
  private Singleton() {
    
  }
  
  public static Singleton getInstance() {
    return singleton;
  }
}

饱汉式:

访问的才提供对象

缺点: 线程不安全

public class Singleton {
  private static Singleton singleton;
  
  private Singleton() {
    
  }
  
  public static Singleton getInstance() {
    if (singleton == null) {
      singleton = new Singleton();
    }
    return singleton;
  }
}

内部类:

内部类可以直接访问外部类中的成员,但外部类不能直接访问内部类,若要访问,必须创建内部类
对象才能访问

内部类本身就是静态的, 用static修饰后类似于一个外部类了

创建一个内部类和对象:

class Test{
  class Inner {
    
  }
}

class Main {
  Inner inner = new Test().new Inner();
}

如果用static修饰内部类, 则该内部类属于该外部类, 但不属于外部类的对象

静态内部类可包括静态成员也可包括非静态成员。根据静态成员不能访问非静态成员的规定,所以静态内部类不能访问外部类实例成员,只能访问外部类的静态成员。

class Test2 {
  static class Inner2 {
    
  }
}

class Main2 {
  Test2.Inner2 inner = new Test2.Inner2();
}

非静态内部类细节

  1. 注意非静态内部类中不能定义静态成员变量和静态成员函数。但可以定义静态成员常量。原因常量
    在生成字节码文件时直接就替换成对应的数字。
  2. 当内部类在外部类成员位置上被私有修饰,在外部类意外的其他地方是无法访问的。只能在外部类
    中访问

以下怎么拿到num:

public class Test {
	public static void main(String[] args) {
		Outer.Inner in = new Outer().new Inner();
		in.show(); 
  }
}

class Outer {
int num = 5;// 外部类的成员变量 
  class Inner {
		int num = 6;// 内部类的成员变量 
    
    void show() {
      int num = 7; // 内部类局部变量 
      System.out.println("内部类局部num=" + num); 
      System.out.println("内部类成员num=" + this.num); 
      System.out.println("外部类成员num=" + Outer.this.num);
}

注意如果外部类的成员为static, 则内部类在访问外部类成员和方法时用外部类名.来访问

内部类本质上是外部类的成员, 所以外部类的private修饰符对内部类无效

为什么内部类可以直接访问外部类的成员,那时因为内部类持有外部类的引用(外部类.this)。对 于静态内部类不持有 外部类.this 而是直接使用 外部类名。

面向对象三大特征:

  1. 封装
  2. 继承
  3. 多态

有人认为抽象也是一种特征, 但并不被公认

一. 封装(Encapsulation):

为了安全性, 将成员私有化, 不让外界访问, 同时提供特定的访问方式, 相当于是一个外部类

class Cat {
  // 首先私有化属性
  private int id;
  private String name;
  private int age;
 
  // 提供对应的公开访问方法
  // get方法:
  public int getId() {
    return this.id;
  }
  
  // set方法
  public void setId(int id) {
    this.id = id;
  }
}

POJO对象(Plain Ordinary Java Object)

  1. 根据封装来写
  2. 私有化属性
  3. 提供公开的setter 和 getter 方法
  4. 至少两个或者以上的构造方法

Java Bean对象:

  1. 所有的成员变量都要使用 private 关键字进行修饰

  2. 为每一个成员变量编写 set、get 方法

  3. 创建一个无参数的构造方法

  4. 创建一个有参数的构造方法

二. 继承(Inheritance):

在面向对象中, 类与类之间可以存在继承关系

Java是一门典型的单继承编程语言

Java中如何实现继承:

关键字 extends

父类(超类, 基类), 子类

private 修饰的属性和方法都是无法被子类继承的

protected 修饰的方法就是用于子类继承的

class RichMan() {
  public int money = 100000000;
  private wife = "wife";
  
  private void play() {
    System.out.println("炒股");
  }
  
  protected void contralCompany() {
		System.out.println("掌控公司");
  }
}

class Son extends RichMan() {
  public static void main(String[] args) {
    Son son = new SOn();		// son中的成员只有money, 方法只有contralCompany
    System.out.println(son.money);
    son.contralCompany();
  }
}

继承的功能:

减少代码的重复, 提高代码的复用度

方法重写(覆盖):

重写(OverWrite)

覆盖(OverRide)

发生在继承中, 指的是, 子类继承了父类方法后不满足使用, 就重写该方法以满足子类使用

重写是访问修饰符权限可以放大但不能缩小, 除了访问修饰符, 返回值和参数还有函数名多保持一致

注解:

@override // 覆盖

@Deprected // 过时

@SuppressWarning // 压制警告

class RichMan() {
  public int money = 100000000;
  private wife = "wife";
  
  public void play() {
    System.out.println("炒股");
  }
}

class Son extends RichMan() {
  
  @Override
  public void play() {
    System.out.println("健身");
  }
  public static void main(String[] args) {
    Son son = new SOn();
    son.play();
  }
}

super关键字:

super 在java中, 是一个指针, 类似于this关键字

this关键字指向创建的每一个对象

super会自动指向父类

super( ); // 调用父类的无参构造

final关键字:

final : 最后

  1. 被他修饰的变量就是常量

    static final

  2. 用final修饰的方法不能被重写

  3. final关键字修饰类则该类不能被继承

为什么类用final修饰:

基于jvm的安全性考虑, 防止被继承之后底层代码被篡改从而引起各种安全问题

对象的创建流程及内存结构三:

  1. java命令将源码(.java)进行编译, 生成字节码文件(.class)
  2. javac命令执行字节码文件
  3. 将字节码文件加载进虚拟机, 具体方法进入方法区(非静态区和静态区)
  4. JVM从静态区中寻找main函数, 并将其加载进栈开始执行程序
  5. main 函数开始执行, 创建对象代码, 如Son son = new Son();
  6. 在堆内存中开辟对对象的内存空间, 并分配地址
  7. 创建成员变量开始初始化
  8. 子类构造函数从非静态方法区加载进栈开始执行
  9. 第一句先执行父类的构造函数
  10. 父类构造函数执行, 为子类继承到的成员变量进行初始化(对象内存空间里的父类空间)
  11. 父类构造函数弹栈执行完成
  12. 子类构造函数继续执行
  13. 再执行子类构造函数的内容, 进行针对性初始化
  14. 执行完成, 子类构造函数弹栈, 将对象的内存空间地址赋予相应的引用变量

instanceof 关键字 判断对象是否为对应类, 配合继承判断

三. 多态(Polymorphism):

在继承的基础上才有多态

父类应用指向子类示例

Animal cat = new Cat( );

访问不到子类自身的方法, 但可以重写父类方法来满足子类使用

多态的好处

提高了程序的扩展性。

多态的弊端

通过父类引用操作子类对象时,只能使用父类中已有的方法,不能操作子类特有的方法。

多态的前提

\1. 必须有关系:继承,实现。 2. 通常都有重写操作

当父类的引用指向子类对象时,就发生了向上转型,即把子类类型对象转成了父类类型。向上转型
的好处是隐藏了子类类型,提高了代码的扩展性。

public class Test {
    public static void main(String[] args) {
        Animal cat = new Cat("小黄", "猫");
        Animal dog = new Dog("小红", "狗");
        PetStore store = new PetStore();
        store.wash(cat);
        store.wash(dog);
    }
}

@Setter
@Getter
class Animal {
    String name;
    String type;

    public Animal() {

    }

    public Animal(String name, String type) {
        this.name = name;
        this.type = type;
    }

    public void beWash() {
			// 这段函数体没意义只用来被重写, 可以用抽象方法从而省去写这个函数
    }

}

class Dog extends Animal {

    public Dog() {

    }

    public Dog(String name, String type) {
        super(name, type);
    }

    @Override
    public void beWash() {
        System.out.printf("%s正在被洗, 是一只%s\n", this.name, this.type);
    }
}

class Cat extends Animal {

    public Cat() {

    }

    public Cat(String name, String type) {
        super(name, type);
    }

    @Override
    public void beWash() {
        System.out.printf("%s正在被洗, 是一只%s\n", this.name, this.type);
    }
}

class PetStore {

    public void wash(Animal pet) {
        pet.beWash();
    }
}

抽象:

抽象方法:

如果一个方法, 不需要实现体(函数内容), 就可以声明抽象方法

抽象方法: 没有方法体的方法, java中使用abstract关键字声明的方法

访问修饰符 abstract 返回值类型 方法名称

抽象方法必须写在抽象类中

抽象类:

被abstract关键字声明的类

访问修饰符 abstract class 类名

抽象父类不写抽象方法, 则子类需要写, 但抽象子类可以不写, 留给子类以后的孙类解决

注意: 抽象类中不一定有抽象方法, 有抽象方法就肯定是抽象类

如果一个类继承了抽象类, 就必须实现抽象方法, 如果一定不实现, 则这个子类也声明为抽象类

抽象类不可以创建示例, 原因: 调用抽象方法没有意义

存在的意义是为了继承给子类, 通过多态调用子类对抽象方法的实现

抽象关键字abstract不可以和哪些关键字共存?

  1. final: fianl修饰的类是无法被继承的, 而abstract修饰的类一定要有子类. final修饰的方法无法 被覆盖, 但是abstract修饰的方法必须要被子类去实现的
  2. static: 静态修饰的方法属于类的, 它存在与静态区中, 和对象就没关系了. 而抽象方法没有 方法体, 使用类名调用它没有任何意义
  3. private: 私有的方法子类是无法继承到的, 也不存在覆盖, 而abstract和private一起使用修饰 方法, abstract既要子类去实现这个方法, 而private修饰子类根本无法得到父类这个方法. 互相矛盾

接口:

接口本质是特殊的类, 特殊抽象类

接口中所有方法都是没有实现的(抽象方法)

在jdk8之前: 接口中的所有属性方法, 默认都是public的, 即使没有用public修饰

java中使用interface关键字来定义接口

接口无法示例化, 必须使用子类, 以多态的形式完成实现

java中, 接口可以多实现多继承

接口的定义和实现:

public interface TestInterface {
	public void say();
  void play();
}

public class MyInterface implements TestInterface {
  
  @Override
  public void say() {
    // 代码
  }
  @Override
  public void play() {
    // 代码
  }
}

在jdk8中接口可以定义普通方法, 但也只能通过多态的方式访问, 用default关键字修饰

public interface Test {
  void show();
  
  public default void func() {
    System.out.println("执行");
  }
}

也可定义静态方法, 相当于把接口做了工具类

public interface Test {
  void show();
  
  public static void func2() {
    System.out.println("执行");
  }
}

接口多实现多继承:

interface A {
  void show1();
}

interface B {
  void show2();
}

// 接口多实现
class test implements A, B {
  public void show1() {
  }
  
  public void show2() {
  }
}

// 接口多继承
interface C extends A, B {
  void show3();
}

接口与抽象类的区别

相同点:

  • 都位于继承的顶端,用于被其他实现或继承
  • 都不能实例化
  • 都包含抽象方法,其子类都必须覆写这些抽象方法

区别:

  • 抽象类为部分方法提供实现,避免子类重复实现这些方法,提供代码重用性
  • 接口只能包含抽象方 法; 一个类只能继承一个直接父类(可能是抽象类),却可以实现多个接口(接口弥补了Java的单继承)

二者的选用:

  • 优先选用接口,尽量少用抽象类
  • 需要定义子类的行为,又要为子类提供共性功能时才选用抽象类

静态导包:

针对于静态方法, 导入成功可以直接使用静态方法而不需要通过类名.的形式访问

例如:

import static java.util.Arrays.sort;

class Test {
  public static void main(String[] args) {
    int[] arr = {1, 2, 34, 1, 2, 5, 76, 4};
    sort(arr);
  }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值