JAVA-面向对象

121 阅读11分钟

思想

面向过程的程序设计思想 process-oriented-programming POP

焦点: 过程->操作数据的步骤 实现代码重复出现, 抽取为一个函数

代码结构: 以函数为组织单位

执行者思维

面向对象的程序设计思想 object oriented programming OOP

焦点: 类 参照现实中事物 将事物属性特征行为 抽象出来 用类来表示

代码结构: 以类为组织单位

设计者思维

面向对象 面向过程 相辅相成

类与对象

  • 类 => 抽象概念的物 属性 行为
  • 对象 => 实实在在的某个物

内存结构

 public static void  main (String [] arg){
   Person p1=new Person ();
   p1.name="杰克";
   p1.age=24;
 }

image.png

  • 方法区: 存放类的模板

类的成员-属性

内存分配

对象属性: 随着对象的创建,存储在堆空间中 随着对象的创建而创建,消亡而消亡

有默认初始值

局部变量: 存储在栈空间中 随着方法对应的栈帧入栈,局部变量在栈中分配,栈帧出栈,则消亡

无默认值 须显式赋值

image.png

类的成员-方法

  • 类/对象 行为特征的抽象 完成某个功能操作
  • JAVA 中类方法 不调用不执行
public static void main(String[] args) {
  Person p1 = new Person();
  p1.sleep(6)
}

image.png

 Student[] stus=new Student[3];
 stus[0] = new Student();
 stus[0].id = 10;
 stus[0].score = 78;

image.png

方法重载

概括

同一类 同名方法 参数列表不同 (个数 , 类型) 多个方法.彼此之间构成方法重构

注意: 重载与形参名, 权限修饰符 返回值类型都没有关系

  • 编译器如何确定调用某个具体方法?

方法名 -> 确定一波重载方法(不同形参列表) -> 具体方法

可变个数形参 方法

// 注意: 可变参数 须声明在形参列表的最后 可变个数确定
 public void print(int  ... nums){}

方法的值传递机制

  • 基本数据类型 值传递
  int m=10;
  int n=m;
  m++;
  // m=11 n=10
  • 引用数据类型 地址传递 new

实参给形参赋值

image.png

基本数据类型传值
public static void main(String[] args) {
  int m = 10;
  int n = 20;
  test.swap(m,n);
}

public void swap(int m, int n){
  int temp = m;
  m = n;
  n = temp;
}

image.png

引用类型传值
class Date {
   int n;
   int m;
}
class Test {
 public static void main(String [] args){
   Test test = new Test();
   Date date = new Date();
   date.m = 10;
   date.n =20;
   test.swap(date);
 }
 pubilc void swap(Date date){
   int temp = date.m;
     date.m=date.n;
     date.n=temp;
 }
}

image.png

递归

  • 自己调用自己的方法 耗内存

  • 计算 n!

 public int getMul(int n){
   if(n == 1) {
     return 1;   
   } else {
     return n * getMul(n-1);
   }
 } 

关键字 package import

package : 用于指明该文件中定义的类,接口 等结构所在的包

import : 告诉编译器到哪里去寻找这个类

  //全类名引用
  java.sql.Date date = new java.sql.Date(12315L);

封装性

因: 把该隐藏的隐藏起来 该暴露的暴露出来

java规定4种权限修饰符 private 缺省 protected public 体现-> 当修饰类及类的内部成员被调用时 体现可见性大小

理论上:

高内聚: 类的内部数据操作细节自己完成 不允许外部干涉 (java程序通常以类的形态呈现,相关的功能封装到方法中)

低耦合 仅暴露少量的方法给外部使用, 尽量方便外部调用 (给相关的类,方法设置权限,把该隐藏的隐藏起来,该暴露的暴露出来)

java修饰符访问范围.jpg

  • ps: 其他包的子类: 不同包通过继承获得关系

应用

  • 场景一: 私有化类的属性 提供公共的get和set方法 set中对属性的判定修改 get 获取
  • 场景二: 将类中不需要对外暴露的方法,设置为private
  • 场景三: 单例模式中构造器private 避免在类的外部创建实例

构造器 constructor

  • 格式: 权限修饰符 类名(形参列表) {}
Person p1 = new Person();
//系统默认提供空参构造器 权限跟类一致 类中显示声明构造器 系统不再提供默认构造器
Person()=> 构造器 public Person(){} 

<init> 方法

  • 在Java中,<init>不是方法或关键字,而是JVM为每个类生成的构造方法的名称。构造方法用于初始化新创建的对象,并且必须与类同名且无返回类型。 image.png

JavaBean

标准java类 java语言写成的可重用组件

  1. 类公共
  2. 无参公共构造器
  3. 有属性,对应的get,set

UML类图 unified modeling Language

image.png

关键字 this

  • this => 当前对象

    属性与形参同名 this.属性 区分属性与形参

    调用构造器 => this();

继承性 inheritance

image.png

class Person {}

class Student extends Person {}

继承后 => 子类继承父类 调用父类构造器 -> 子类获取到父类中声明的所有属性和方法 private 须get set 子类不可以直接调用

Java中声明的类,默认继承于 Java.lang.Object

image.png

classDiagram
Animal <|-- Duck
Animal <|-- Fish
Animal <|-- Zebra
Animal : +int age
Animal : +String gender
Animal: +isMammal()
Animal: +mate()
class Duck{
+String beakColor
+swim()
+quack()
}
class Fish{
-int sizeInFeet
-canEat()
}
class Zebra{
+bool is_wild
+run()
}

总结

继承.jpg

方法重写 overwrite/override

  • 子类对父类继承过来的方法进行覆盖
//重写 Object=>equals 方法
@Override
public boolean equals(Object o) {
    if (this == o) {
        return true;
    }
    if (o instanceof Teacher) {
      Teacher teacher=  (Teacher) o;
      return this.age==teacher.age && this.name.equals(teacher.name);
    }
  return false;
}

关键字 super

  • super 父类的 (继承中)
//方法
super.eat()
//构造器
super(形参列表)

子类对象实例化全过程

子类构造器创建对象时, 子类构造器一定会直接或间接的调用到其父类的构造器,直到Object类中构造器为止

正因调用父类的构造器 将父类中声明的属性方法加载到内存中供子类对象使用

  • 创建子类的对象时,内存中到底有几个对象?

    一个对象,即为当前new后面构造器对应的类的对象

多态性

使用前提 1.继承 2. 方法的重写 理解: 一个事物的多种形态 方法的多样

//子类的对象赋给父类引用
//针对创建的对象 内存中加载了Man
Person p2 = new Man();
// 虚拟方法调用 编译时 认为方法是父类的类型方法
// 执行时 实际执行的是子类重写父类的方法
p2.eat();
//ps: 属性不适用 
Person id=1001
Man id =1002
p2.id => 1001

image.png

多态 多用于:

public void adopt(Animal animal) {
  animal.eat();
}
// Animal animal = new Dog();
test.adopt(new Dog);

多态 符合 开闭原则 open closed principle 扩展开放 修改关闭

向下转型

// 父类引用 针对创建的对象 内存中加载了Man中特有方法+属性 p2不可以直接调用
Person p2 = new Man();
//向下转型 m1 可调用Man中特有方法+属性
Man m1 = (Man) p2;
// a instanceof A/superA 判断对象a是否是类A/A的父类的实例
if(p2 instanceof Man) => true

总结

多态性.png

Object

类 java.lang.Object 是类层次结构的根类 没有声明属性

equals()

// Object中定义 比较两个对象是否指向了堆空间中同一个对象实体
public boolean equals(Object obj) {
    return (this == obj);
}
//String,File,Date 或 包装类 重写equals()方法 比较实体内容是否相等
//String中定义
public boolean equals(Object anObject) {
    if (this == anObject) {
        return true;
    }
    if (anObject instanceof String) {
        String anotherString = (String)anObject;
        int n = value.length;
        if (n == anotherString.value.length) {
            char v1[] = value;
            char v2[] = anotherString.value;
            int i = 0;
            while (n-- != 0) {
                if (v1[i] != v2[i])
                    return false;
                i++;
            }
            return true;
        }
    }
    return false;
}

== 和 equals() 区别

  • ==
  1. 基本数据类型 : 判断数据值是否相等
   char c1 = 'A';
   int i1 = 65;
   c1 == i1  =>  true 
  1. 引用数据类型 : 两个引用变量地址值是否相等
  • equals 方法

    引用数据类型 : 对类来说 重写equals() 与 不重写equals() 区别

    toString()

 //Object类中 toString() 定义
public String toString() {
    return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
// 子类使用说明
// 自定义类 没有重写Object类的toString() 默认返回当前对象地址值
// String File Date /包装类 重写toString() 返回当前对象实体内容

/**
 * String 中 toString()方法
 * This object (which is already a string!) is itself returned.
 *
 * @return  the string itself.
 **/
public String toString() {
    return this;
}

//自定义类 toString() 重写
@Override
public String toString() {
    return "Teacher{" +
            "age=" + age +
            ", name='" + name + ''' +
            '}';
}

关键字 static

由来:

  1. 某些特定的数据在内存空间里只有一份 共享
  2. 有些属性/方法的调用者和当前类的对象无关 => 类属性 类方法

静态变量: 类中的属性使用static进行修饰

静态变量 与 实例变量 (方法类似)

个数: 静态变量 内存空间只有一份 共享 实例变量: 每个实例都保存一份实例变量

内存位置: 静态变量 存放堆空间 实例变量 存放堆空间对象实体中

加载时机:

静态变量 随类加载而加载 类卸载而消亡

实例变量 随对象创建而创建 对象消亡而消亡

内存解析

class Person {
  String name;
  int age;
  static String nation;
}
public static void main(String[] args) {
  Person c1 = new Person();
  c1.name = "姚明";
  c1.age = 42;
  Person.nation = "中国"; //或者 c1.nation = "中国";
}

image.png

单例模式 singleton

采取一定方法保证在整个软件系统中 对某个类 只存在一个对象实例 该类只供一个取得其对象实例的方法

image.png

饿汉式

立即加载 类加载 -> 唯一实例就创建 线程安全 内存占用时间长 例: java.lang.Runtime 类


class Bank {
  private Bank(){}
  private static Bank instance = new Bank();
  public static Bank getInstance(){
   return instance;
  }
}

懒加载

延迟加载 使用时,创建 省内存空间

 class Bank {
  private Bank(){}
  private static Bank instance = null;
  public static Bank getInstance(){
   if(instance == null) {
     // 存在同时创建实例的可能 线程不安全
     instance = new Bank();
   }
   return instance;
  }
}

类的成员-代码块

// 初始化类或对象信息
// 可static 修饰 静态代码块 初始化类信息
static { 
 ...
}
//{} 非静态代码块 
{ 
 ...
}

类的非静态属性 (实例变量) 赋值

  1. 默认初始化 int i;
  2. 显式初始化 int i = 1; / 5. 代码块中初始化 { i = 1; }
  3. 构造器中初始化 public Test() { i = 1; }
  4. 有对象后,对象赋值 test.i=1;

先->后 顺序 1 -> 2/5 -> 3 -> 4

关键字 final

final 最终的

修饰类 表示 此类不能被继承

修饰方法 此方法不能被重写

修饰变量 常量 一旦赋值,不可更改

final + static 全局常量

抽象类 和 抽象方法

image.png

abstract class Life{

    int isLife;
    /**
     * 吃东西
     */
    public abstract void eat();
}

模板方法 - 设计模式

应用: 抽象类作为多个子类的通用模板

接口 interface

本质 : 标准 规范 定制后大家都遵守 interface

  • 属性 默认 public static final
  • 方法 默认 public abstract
接口
单继承 一父可多继承接口
多实现 多接口

image.png

interface  A{

}
interface B {

}
interface C extends A ,B{


}
class Test implements A ,B{
}

public  class Teacher extends Person implements Eat , Look{

}
//接口多态性
//接口         实现类对象
Usb usb = new Printer();

jdk8 和 jdk9 接口方法新特性

jdk 8 之前 抽象方法 public abstract

jdk 8 可 声明静态方法(只可接口使用) 默认方法

jdk 9 可 声明私有方法

//默认方法
default void method() {
 ...
}
//实现类调用
classA.super.method();

抽象类与接口 对比

image.png

类的成员-内部类

  • 将一个类A(内部类)定义在一个类B(外部类)里面

例子 1. Thread 类的内部 state类 线程生命周期 2. HashMap 类声明Node类 表封装的key和value

class Person {
  static class Eat{}
  class Work{}
}

//使用
new Person.Eat();
new Person().new work();

匿名类使用

//提供接口 匿名实现类的匿名对象
new Comparable(){
    @Override
    public int compareTo(Object o) {
        System.out.println("你好");
        return 0;
    }
}.compareTo(person); //对实现方法的使用

枚举类

针对于某个类 其实例是确定个数的

image.png

interface Info {
    /**
     * 展示
     */
    void show();
}

public enum Season implements Info{
    //默认修饰 public static final
    // 在实例中 重写方法 执行不同方法
    //使用 Season.SPRING.show();
    SPRING("春天") {
        @Override
        public void show() {
            System.out.println("春天到了");
        }
    },
    AUTUMN("秋天") {
        @Override
        public void show() {
            System.out.println("秋天到了");
        }
    }
    ;
    private final String name;

    /**
     * 默认private 修饰
     * @param name
     */
    Season(String name) {
        this.name = name;
    }

    /**
     * 公共方法 重写
     */
//    @Override
//    public void show() {
//        System.out.println("学习时间到");
//    }

}

annotation注解

  • 被编译器或其他程序读取,做出相应的处理
// 例
@Transactional
//元注解 : 对现在注解进行解释说明的注解
@Target => 使用范围

@Retention => 描述注解生命周期

单元测试

JUnit测试 -> 白盒测试 如何完成成功(HOW) 能完成什么样(What)

  • jar包准备 : junit + hamcrest-core
@Test
public void test(){
   System.out.println("hello");
}

包装类

对基本数据类型进行包装 使得具备引用数据类型变量相关特征

Object->equals(Object obj) 基本数据类型不可用

image.png

ps: 成员变量默认值为null

内存解析

public static void main(Sting[] args){
  int num = 520;
  Integer obj = new Integer(520);
}

image.png

自动装箱与拆箱

java 5.0 新特性

int i = 10;
Integer n = i;  // 自动装箱 valueof()
int i2 = n; //自动拆箱 xxxValue()

类型转换图

image.png

包装类缓存机制

image.png image.png

Boolean源码案例

image.png

image.png