Java基础——面向对象

1、面向过程、面向对象的区别

面向过程:考虑怎么做(具体在于过程)。

面向对象:考虑谁来做(具体在于谁,即在于对象)。

2、类和对象的关系

类:主要用于从对象抽象出一些公共特征,形成一个类。

对象:万事万物皆对象,可以是具体的事物、实体、实例。

3、面向对象三个阶段

OOA(Object Oriented Analysis):面向对象分析

比如猫、 狗、仓鼠等 ====> 抽象出一个类:宠物
比如宠物 、昆虫等 ====> 抽象出一个类:动物

OOD(Object Oriented Design):面向对象设计

比如宠物有什么行为和特征

  • 行为:吃饭、睡觉等 ===> eat、sleep等方法
  • 特征:品种、肤色等 ===> kind、color等属性

OOP(Object Oriented Programming):面向对象编程

比如具体的eat方法 ===> public void eat{System.out.print(“正在进食,请勿打扰!!!”)}

4、创建类

类包括:属性、方法、构造器、代码块、内部类。

5、创建对象的生命周期

创建对象过程:

  1. 对类加载,只加载一次。
  2. 在堆中开辟空间。
  3. 对对象初始化操作,属性默认初始化赋值。
  4. new关键字调用构造器重新赋值。

6、局部变量和成员变量

6.1、局部变量和成员变量区别

区别局部变量成员变量
位置不同方法中类中方法外
内存位置不同栈内存堆内存
作用范围不同当前方法中(当前代码块中)当前类的很多方法
作用时间不同方法执行到执行完毕对象创建到销毁
是否有默认值有初始化值
是否要初始化需要,否则在操作会报错无需初始化

6.2、基本类型初始化默认值

引用类型默认值:null

基本数据类型默认值
byte(byte)0
short(short)0
int0
long0L
float0.0f
double0.0d
booleanfalse
char‘/u0000’(null)

7、构造器

构造器的特点:

  1. 无返回值
  2. 没有返回类型
  3. 构造器名字应与类名一致
  4. 不可被final、static、abstract等修饰

构造器的作用:给属性赋值。(并不是创建对象)

8、this

this代表当前对象

this修饰变量:如果局部变量或者参数与成员变量名称相同,用this修饰代表使用的是成员变量,避免就近原则

this修饰方法:同一个类方法互相调用,this可省略不写

this修饰构造器:同一个类中的构造器可用this互相调用

this修饰构造器必须放在第一行
原因:为了避免多次调用构造器给对象初始化赋值,同一方法内只能调用一次this()或super() ===> 由于构造器中第一行如果没有this()或super(),默认会有一个super()。如果this和super都存在就会多次调用父类构造器

9、static

修饰:属性、方法、代码块、内部类。

9.1、修饰属性

多线程共享变量可用static修饰

  • 在类加载时加载到方法区的静态域中
  • 先于对象存在
  • 调用方式:类.属性名、对象.属性名
9.2、修饰方法
  • 在类加载时加载到方法区的静态域中
  • 先于对象存在
  • 静态方法中不能访问非静态属性和方法
  • 静态方法中不能用this(由于先于对象存在)
  • 调用方式:类.方法名、对象.方法名
9.3、修饰代码块

static修饰代码块,叫静态代码块,最先执行。

9.4、修饰内部类

static修饰的内部类,可以作为普通类来使用。

10、代码块

代码块分类:普通块,构造块,静态块,同步块(多线程)

代码块执行顺序:

  1. 最先执行静态代码块
  2. 执行构造块
  3. 执行构造器
  4. 方法中的普通代码块

块

11、包、import

11.1、包

标准:

  • 包名小写
  • 域名倒写
  • 用 . 分隔
  • 不能使用关键字
  • 包声明位置一般在非注释代码的第一行

11.2、import

  1. 使用不同类的,需要导包
  2. 导包以后,还想用其他包下同名的类,需要手动写包。
  3. 同一个包下的类无需导包,直接使用
  4. 在java.lang下的类也无需导包,直接使用
  5. 可导入*,导入全部的;

特殊用法:

通过 import static java.lang.Math.*; 导入Math中所有静态方法,直接调用静态方法名使用。

import

12、面向对象的三大特征:封装、继承、多态

12.1、封装

封装:隐藏内部复杂的具体代码,对外提供简单接口调用。

封装的好处:提高代码的可扩展性、可维护性和安全性。

利用访问修饰符控制外界访问。

实际开发中,利用 private修饰属性,对外提供 setter,getter方法。

12.2、继承

继承:子类继承父类定义的内容。

继承的好处:

  • 提高代码的复用性,子类可复用父类代码
  • 便于代码的扩展
  • 为了多态的使用

继承的特性:

  1. 父类private修饰的内容,子类实际上也继承,只是因为封装的特性阻碍了直接调用,但是提供了间接调用的方式,可以间接调用。
  2. 一个父类可有多个子类
  3. 一个子类只能有一个父类(但可以间接地继承其他类)
  4. 继承具有传递性,所有类都间接或直接继承Object类。
12.2.1、权限修饰符
权限修饰符同一个类同一个包子类所有类
private
default
protected
public
12.2.2、方法的重写

重写:子类重写父类方法,参数名和参数列表 (个数、类型、顺序) 必须相同。

12.2.3、重写和重载区别
英文位置修饰符返回值方法名参数列表抛出异常
重载overload同一类中无关无关相同必须不同无关
重写override子类父类中父类小于等于子类父类返回值类型大于等于子类相同相同父类异常大于等于子类
12.2.4、super

super修饰属性和方法:显式地调用父类的属性和方法。
(在父类属性或方法与子类重名时,只能通过super.属性或方法调用)

所有构造器的第一行默认情况下都有super(),但是一旦构造器中显式地使用super调用了父类构造器,那么这个super()就不会给你默认分配了。

如果构造器中没有显式地调用父类构造器的话,那么第一行都有super(),调用父类空构造器,可以省略不写。

12.2.5、继承条件下构造器执行过程

在这里插入图片描述

12.2.6、Object类

所有的类都直接或间接的继承自Object类。

如果类未声明继承的父类,则默认extends Object。

12.2.6.1、toString()

Object-toString

return getClass().getName() + “@” + Integer.toHexString(hashCode());
返回:全路径名 + “@” + 将对象地址进行哈希算法,并转化为十六进制再转化为字符串

一般来说,有需求的话,可对 toString()方法重写。

12.2.6.2、equals()

Object-equals

顶级父类Object的equals比较的是地址(==)。

一般来说都会重写equals方法

12.2.6.3、链接到面试:为什么重写equals要重写hashCode?

原因:

  1. 根据hashCode规则,相同对象必须有相同哈希值,因此重写equals一定要重写hashCode。
  2. 对于自定义的类,比如Student类,一般两个new Student内存地址不一样,而默认hashCode是根据对象的内存地址来计算得到的,两者会不相等,在实际开发中呢,比如只要学号相等我就认为是同一个学生了,这时就要让hashCode根据学号计算生成。
  3. 对于一些集合,例如HashSet(要通过hashCode计算哈希值,再通过表达式计算所处位置,最后通过equals比较是否相等。) 如果只重写一个,很可能两者会不一致,如下▽
        特别是自定义的类,比如new Student(1,“张三”)和new Student(1,“张三”),这两个对业务来说是相等的,但是如果未重写其中一个就会导致不一致,因为HashSet底层是HashMap(key有许多地方都会比较hashCode和equals)
    在这里插入图片描述
12.2.6.4、类与类的关系
  1. 继承关系

一个类继承另一个类,通过extends标识

  1. 实现关系

一个类实现一个interface接口,通过implements标识

  1. 依赖关系

一个类A使用到另一个类B,类B作为参数被类A在某个方法中使用

  1. 关联关系

比依赖更强的关系,类B作为类A的属性被使用

  1. 聚合关系

比关联更强的关系,整体与部分的可分离关系,如公司和员工

  1. 组合关系

比组合更强的关系,整体与部分的不可分离关系,如人和眼睛、心脏、大脑等
类与类的关系

几种关系所表现的强弱程度依次为:组合>聚合>关联>依赖。

12.3、多态

多态:相同的行为,在不同子类中表现出不同的行为特性。

多态的体现:

  • 继承
  • 实现
  • 重写
  • 向上、向下转型

总结:父类引用指向子类对象

多态的好处:

  1. 提高代码的灵活性、扩展性
  2. 开闭原则:对扩展开放,对修改关闭
12.3.1、多态的案例

父类:Person

public class Person {

    protected String name;
    protected Integer age;
    
    public Person(){
        
    }
    
    public void eat(){
        System.out.println("Person:" + name + ",eat");
    }
}

子类:Student

public class Student extends Person{
    
    private String sno;
    
    public Student(String sno){
        // super();
        this.sno = sno;
    }
    
    public void study(){
        System.out.println("Student:" + name + ",study");
    }

}

测试代码:

多态演示

总结:
Person stu = new Student(“11812”);
左侧:编译期的类型 = 右侧:运行期的类型
只能使用父类的方法,不能使用子类独有的方法
(如果要使用子类独有的方法,可构造子类对象、向下转型为子类)

12.3.2、继承和泛化

继承:先有父类,后有子类。

泛化:先有子类,后有父类。

13、final

final修饰变量:变量值不可修改,变成了常量,一般用大写字母表示

final修饰引用类型:这个引用类型的地址不可更改,其内容是可更改的。

final修饰方法:这个方法不能被子类重写

final修饰类:这个类不能被继承,没有子类;(其中方法也没必要用final修饰,因为都不能被继承,就不必考虑方法是否能被子类重写)

14、抽象类和抽象方法

14.1、简介

抽象类:抽象出主要的行为和特征为一个抽象类(抽象类可定义n个抽象方法)

抽象类设计目的:抽象类设计的初衷就是给子类继承用的

抽象类的作用:定义一个子类通用的模板,给子类添加某些约束和限制,使子类设计更加规范。

抽象类案例:

// 如果一个类中有一个抽象方法,那么这个类也要变为一个抽象类
public abstract class Person {
    
    protected String name;
    
    protected String sex;
    
    // 如果有子类对这个方法很满意,则无需重写,直接使用。
    public void say(){
        System.out.println("say");
    }
    
    // 子类永远不满意父类方法,必须重写。
    // 没有方法体且被abstract修饰,为抽象方法
    public abstract void eat();
    
    public abstract void sleep();
}

// 抽象类可被其他类继承
// 子类继承抽象父类,一般重写父类的所有抽象方法
// 如果没有重写父类的所有抽象方法,则子类也可变为一个抽象类
class Student extends Person{

    @Override
    public void eat() {
        System.out.println("student eat");
    }

    @Override
    public void sleep() {
        System.out.println("student sleep");
    }
}

// 一个类继承抽象类,也可变为抽象类
abstract class Emp extends Person{
    
} 

14.2、链接到面试

14.2.1、抽象类不能创建对象,那么抽象类是否有构造器

抽象类有构造器,子类初始化对象调用构造器默认调用super,先调用父类的构造器。

14.2.2、抽象类是否可被final修饰

不可以,抽象类的定义就是为了给子类继承,规范子类,而被final修饰的类不能被继承。

15、接口

一个类实现一个接口,那么就要重写接口中所有的抽象方法。(否则只能成为抽象类)

15.1、JDK1.8之前

接口只有两部分内容:

  • 常量:默认添加 public static final
  • 方法:默认添加 public abstract
[访问修饰符] interface 接口名 [extends 父接口1、2……]{
	定义常量;
	定义方法;
}

示例:

public interface InterfaceTest {
	/*public static final*/ String S = "s";
	/*public abstract*/ void test();
}

15.2、JDK1.8之后

新增一部分内容:

  • 非抽象方法:public default 修饰的非抽象方法
    • 注意:
      • 1、default 必须有
      • 2、重写default修饰的方法时,实现方法上不能加default,否则报错
  • 静态方法:
    • 注意:
      • 1、static必须有
      • 2、静态方法不能被实现
15.2.1、非抽象方法的作用

非抽象方法的作用:在实现此接口较多的类时,添加共同的行为。(为了避免新增一个抽象方法,导致所有实现类都要重写。简而言之,避免繁琐的重复实现

非抽象方法的实际目的:为了接口升级,方便修改接口。

15.2.2、静态方法的作用

静态方法的作用:为接口提供与接口相关的工具方法。

静态方法的实际目的:为了接口升级,方便修改接口。

15.3、接口和抽象类的区别

1、接口无构造器,抽象类有构造器。
2、接口是用来实现的,抽象类是用来继承的。实现能多实现,继承只能单继承(接口可以多继承)。
3、jdk1.8之前接口只有public static final修饰的变量以及public abstract修饰的方法,jdk1.8之后新增静态方法和public default修饰的非抽象方法。抽象类可以有被其他修饰符修饰的变量和独有的(不被abstract修饰的)方法。
4、接口无构造块和静态代码块,抽象类可以有。

16、内部类

类中类。

16.1、成员内部类

位置:在类中,方法外。

16.1.1、非静态成员内部类

具体如下:

public class Outer {

    int age = 20;

    class Inner {
        int age = 10;
        String name;

        public void innerMethod() {
            // 内部类访问当前类方法
            outerHello();
            int age = 33;
            // 内部类访问外部类
            System.out.println(age);
            System.out.println(this.age);
            System.out.println(Outer.this.age);
        }
    }
    
    public void outerHello(){
        System.out.println("outerHello");
    }
    
    public void outerMethod(){
        // 外部类要访问内部类,需要创建内部类对象访问
        Inner inner = new Inner();
        inner.innerMethod();
    }
    
    public static void main(String[] args) {
//        Outer outer = new Outer();
//        Outer.Inner inner = outer.new Inner();
//        inner.innerMethod();
        Outer.Inner inner = new Outer().new Inner();
        inner.innerMethod();
        
    }
}

效果:

在这里插入图片描述

16.1.2、静态成员内部类

特点:

  • 静态成员内部类可以当作普通类使用
  • 静态成员内部类只能访问外部被 static 修饰的属性和方法

如下图:静态类访问外部类的非静态属性和方法报错。

在这里插入图片描述

16.2、局部内部类

位置:方法内。

局部内部类访问的局部变量必须被final修饰。

原因:局部变量会随着方法调用结束而消失,但是局部内部类可能因为使用的对象存在而没有消失,所以为了避免因局部变量消失,而导致访问了已经销毁的变量出现问题,局部内部类访问的局部变量必须被final修饰。

在这里插入图片描述

16.2.1、如果类在项目中只使用一次,那么直接使用内部类或者匿名内部类即可
public class LocalClassTest {

    int num = 0;

    public Comparable<LocalClassTest> getComparable() {
        return new Comparable<LocalClassTest>() {
            @Override
            public int compareTo(LocalClassTest o) {
                return LocalClassTest.this.num > o.num ? 1 : LocalClassTest.this.num == o.num ? 0 : -1;
            }
        };
    }

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值