Java面向对象编程

注解#

  1. 注解(Annotation)也被称为元数据(Metadata),用于修饰解释 包、类、方法、属性、构造器、局部变量等数据信息。
  2. 和注释一样,注解不影响程序逻辑,但注解可以被编译或运行,相当于嵌入在代码中的补充信息。
  3. 在 JavaSE 中,注解的使用目的比较简单,在 JavaEE 中注解占据了更重要的角色,例如用来配置应用程序的任何切面,代替 java EE 旧版中所遗留的繁冗代码和 XML 配置等。

三个基本的 Annotation:

  1. @Override: 限定某个方法,是重写父类方法, 该注解只能用于方法
  2. @Deprecated: 用于表示某个程序元素(类, 方法等)已过时
  3. @SuppressWarnings: 抑制编译器警告

JDK 的元注解 用于修饰其他 Annotation

  1. Retention //指定注解的作用范围,三种 SOURCE,CLASS,RUNTIME
  2. Target // 指定注解可以在哪些地方使用
  3. Documented //指定该注解是否会在 javadoc 体现
  4. Inherited //子类会继承父类注解

包 package#

相当于文件夹,一个包下有很多类文件

定义: package com.company.项目.模块
导入: import package com.company.项目.模块


访问修饰符#


final 关键字#

1) final修饰类时,不让子类继承:public final class A{}

2) final修饰属性时, 属性名大写就是常量:public final int CL;
- 常量可以在定义直接赋值
- 常量可以在构造器上赋值
- 常量可以在代码块上赋值

3) final修饰static静态属性时,只能在定义就赋值,或者在static{}静态代码块里面赋值
- final 和 static 搭配,底层编译器做了优化,在调用这个静态属性时不会类加载了

4) final修饰方法时,子类不能override方法重写了 (如果类已是final,方法就没必要定义final了)


this关键字(对象):#

  1. this 关键字可以用来访问本对象的属性、方法、构造器

  2. this 用于区分当前对象的属性和局部变量

  3. 访问方法的语法:this.方法名(参数列表);

  4. 访问构造器语法:this(参数列表); 注意只能在构造器中使用(即只能在构造器中访问另外一个构造器, 必须放在第一条语句)

  5. this 不能在类定义的外部使用,只能在类定义中使用。


abstract 关键字(抽象)#

1)修饰类时,叫抽象类,不能被实例化,作用于设计。
★ 延伸 模板设计模式(设计好abstract类后定义一个已实现的方法和一个abstract方法,让多个子类继承该抽象类并实现其中的abstract方法,利用类多态 new对象,结合动态绑定机制来完成模板形式)

2)抽象类可以没有abstract方法, 但一旦类包含了abstract方法,这个类必须声明为abstract

3)abstract修饰方法时,叫抽象方法,!!!没有方法体!!!

4)abstract只能修饰类和方法,不能修饰属性和其他

5)抽象类可以有任意成员【普通方法、构造器、静态属性等】

6)如果一个类继承了抽象类,则它必须实现抽象类的所有抽象方法,除非它也声明为abstract

7)抽象方法不能用private、final、static,因为这仨不能重写override


interface(接口)#

1)接口不能被实例化,接口修饰符只有public和默认,接口能被类实现多继承 class A implements I01, I02, I03

2)interface里的属性默认是 public static final int a = 1; !!!因为是常量定义时必须赋值!!!

3)interface里的方法默认是 public abstract void func(); !!!没有方法体!!!

4)类继承类:class A extends B { @override } ===> 类实现接口: class A implements I { @override }

5)普通类实现接口,必须重写(override)所有的方法; abstract类实现接口,可不需要override方法

★ 接口的多态体现

  • implements实现了接口的类, 可以用接口当做参数接对象 work(Interface_ obj)

  • 接口多态数组

  • 接口多态传递


接口和抽象类的区别#

1)接口能被多实现 ====== 抽象类只能单继承

2)接口的多继承能实现让一个类 多功能复用 ====== 抽象类能实现模板设计模式

3)两者都不能被直接实例化, 接口没有构造器,没有普通方法 ====== 抽象类有构造器,也有普通方法

4)接口中的所有方法的修饰符都是public,(Java8后,接口可以包含默认方法(default)和静态方法) ====== 抽象类中的普通方法能定义任何修饰符


enum(枚举) 和 class(类) 的区别#

意思:一个一个列出值,它是有穷且不重复的对象序列集

Java实现枚举有两种方法:

方法一:定义class实现

1)把属性设置成private,构造器也私有化, 只需要get方法不要set方法
2)在类里自定义对象, public static final 常量 = new CLASS(..)
3)toString()


方法二:enum关键字创建,enum与类相似, 用Javap工具反解析得下图

1)enum关键字创建枚举,底层是继承了Enum类的(不能再继承别的类了,但可以实现多接口),而且是个被final修饰的类

2)传统的在类部实例 public static final Season2 SPRING = new Season2("春天", "温暖"),...; 简化成 SPRING("春天", "温暖"), 这里必须知道,它调用的是哪个构造器,实例是放在首位

3)如果使用无参构造器 实例 枚举对象,则实参列表和小括号都可以省略

enum枚举的方法#

  1. 类.values(), 得到它类的所有对象,用图一加强版for可以打印出来

  2. People.XF.ordinal(),得到对象在枚举里的索引号

  3. People.XF.compareTo(People.XH), 第一个数索引号减去第二个数索引号

  4. toString:Enum 父类已经重写过了,返回的是当前对象名,enum类可以重写该方法,用于返回对象的属性信息

  5. name:返回当前对象名(常量名),子类中不能重写

  6. valueOf: People xm = People.valueOf("xm"); xm就是枚举对应"XM"的对象


类的五大成员#

一. 属性(也叫字段field、也叫成员变量)#

  • 普通属性的语法
    定义语法:访问修饰符 数据类型 变量名;
    访问语法:对象名.变量名 ===> cat.name

  属性的细节

  1. 属性定义默认值:public int num = 10;

  2. 访问修饰符有:public, proctected, 默认, private

  3. 属性类型可以是基本数据类型,也可以是引用类型(对象,数组)

  4. 属性值只定义不赋值会有默认值
    (int 0,short 0, byte 0, long 0, float 0.0,double 0.0,char \u0000,boolean false,String null)


  • 静态属性(static关键字)
    定义语法:访问修饰符 static 数据类型 变量名;
    访问语法:类名.静态属性名 Cat.name

  static 静态属性的细节

  1. 某个类中的所有对象共享 静态属性的值

  2. 静态属性在类加载时就初始化了, 没有实例化对象也能访问静态属性

  3. ★ static值共享,延伸单例模式(还没创建构造器就new对象 为饿汉模式, 判断静态属性是否为null,为null即new 对象)



二. 方法#

  • 普通方法的语法
    定义方法:访问修饰符 数据返回类型 方法名(形参) {方法体};
    调用方法:对象名.func()

  方法的细节 (驼峰命名法)

  1. 访问修饰符有:public, proctected, 默认, private

  2. 返回类型:①. void 是可以没有return, ② 返回类型可以为任意类型,包含基本类型或引用类型(数组,对象), 必须有return

  3. 可变参数:定义方法时,参数的个数不确定,可以用 int... (它是一个数组) public int func(int... arr){}

  4. 在同一个类中,方法里调用方法 是直接调用 b.func()

  5. 在不同类的中,方法里调用方法 是创建对象后再调用 (与访问修饰符有关) B b =new B(); b.func()

  6. Java允许同一个类中多个同名同功能但参数个数不同的方法,此为 方法重载 Overload


  • 静态方法的语法(static关键字)
    定义方法:访问修饰符 static 数据返回类型 方法名() {}
    调用方法:类名.func()

  静态方法注意的细节

  1. 类方法和普通方法都是随类加载而加载的,普通方法有this,类方法没有
  2. 类方法中只能访问静态static属性,静态方法。 不能调用普通属性/方法,
    ★ 但普通方法既可以调用静态的方法属性,也可以调用普通方法属性

★ 调用方法时,在内存走向#


★ 方法传参机制(重点!!)#

  • ① 方法一旦被调用时,会创建临时栈区处理方法体内的代码, 方法体结束后临时栈区就消失
  • ② 方法传入的实参是基本数据类型 是与方法外的数据隔离(不影响)
  • ③ 方法传入的实参是引用数据类型 是与方法外共用(影响)

★ 方法递归调用(重要!!)#

  • 规则

    1. 必须向退出递归条件逼近;
    2. 两种条件,必须有一个条件是有具体 return 值,然后步步逼向 return值的条件
  • 递归流程图

  • 阶乘的递归


三. 代码块 {}#

说明:

  1. 有两种代码块形式 普通代码块 和 static代码块

    • static代码块,类被加载它就会执行,只执行一次
    • 普通代码块,实例new一次,执行一次
  2. {}里面可写:输入、输出、方法调用、循环、判断

  3. 相当于构造器的补充机制,在加载构造器前就会调用
    如果全部构造器都需要加载某些语句,可以把这些语句写在代码块里,实现构造器语句复用


四. 构造器 constructor:#

  • 用处:在创建对象时,系统会自动的调用该类的构造器完成对象的初始化。
  • 注意1:`类默认有一个无参数构造器`,如果定义了有参构造器,默认的构造器就会被替代
  • 注意2:构造器就是一个方法,名字必须和类名一样,必须是没有返回值的
class Dog {
    String name;

    //构造器
    public Dog(String name, int age){
        //this.name 就是当前对象的属性 name
        this.name = name;
        System.out.println("this.hashCode=" + this.hashCode());
    };
}

五. 内部类inner class#

  • 定义:一个类的内部又完整的嵌套了一个类,内部叫inner class,外部叫outer class
  • 特点:内部类可直接访问私有属性,并体现类与类的包含关系

定义类在局部位置(方法中/代码块) :(1) 局部内部类(有类名) (2) 匿名内部类(无类名)
定义在成员位置 (1) 内部类 (2) 静态内部类


局部内部类

局部内部类细节:
1)内部访问外部 所有成员都是直接访问,包括私有的

2)外部类访问内部类 实例化对象,再访问

3)局部内部类不能有修饰符,因为它只是一个局部变量 (但可以用final)

4)外部类和局部类成员重名时,默认遵循就近原则, 如必须引用外部类时使用 ===> 外部类.this.成员


匿名内部类
其实就是创建一个类名为:"外部类名$1" 继承 或 实现 外部类/接口, 赋值给 tiger

匿名内部类细节:
1)内部访问外部 所有成员都是直接访问,包括私有的

2)外部类访问内部类 不能访问

3)局部内部类不能有修饰符,因为它只是一个局部变量

4)外部类和局部类成员重名时,默认遵循就近原则, 如必须引用外部类时使用 ===> 外部类.this.成员

★ 匿名内部类使用场景:
把接口当做参数,调用接口上的方法, 利用匿名内部类当做接口的多态形式传进去直接重写接口的方法


成员内部类
细节:

1)内部访问外部 所有成员都是直接访问,包括私有的

2)外部类访问成员内部类 实例化对象,再访问

3)外部其他类访问成员内部类,第一种方法:在外部类创建一个get方法 new出成员内部类;第二种在下图

4)局部内部类可用任何修饰符,它只是一个类成员

5)外部类和局部类成员重名时,默认遵循就近原则, 如必须引用外部类时使用 ===> 外部类.this.成员


静态内部类
细节:

1)内部访问外部 只能访问有带static的成员,包括私有的

2)外部类访问静态内部类 实例化对象,再访问

3)外部其他类访问成员内部类,第一种方法:在外部类创建一个get方法 new出成员内部类;第二种在下图

4)局部内部类可用任何修饰符,它只是一个类成员

5)外部类和局部类成员重名时,默认遵循就近原则, 如必须引用外部类时使用 ===> 外部类.成员


注意

★ 类什么时候被加载#

① 实例对象时(new),会加载类

② 子类对象实例时(继承类),先加载父类再加载子类

③ 使用类的静态成员时 (静态属性、静态方法),会加载类


对象#

★ 创建对象时,加载类的执行顺序#

★ 实例化对象后,给属性赋值在内存上的加载顺序#

★ 引用和复制区别#

对象的引用 Person p1 = p2;#

对象的复制#

class Copy{
    // 创建一个返回对象的方法
    public Dog copy_obj(Dog g){
        Dog copy = new Dog();
        copy.name = g.name;
        copy.age = g.age;
        return copy;
    };
};

对象比较操作符 instanceof#

其与 > , < ,== 同属于运算符
注意: instanceOf 比较操作符,用于判断对象的运行类型是否为 XX 类型或 XX 类型的子类型
用法: System.out.println(aa instanceof AA); // 返回true / false


对象的equals() 方法#

Object对象,原始对象定义有一个equals() 方法, 引用对象的变量名id编号相等,才返回true
String、Integer对象继承了Object对象,equals()方法重写了, 值相等就行,就返回true


对象的hashCode() 方法#


Object的toString() 方法#

注意 System.out.println(obj); ====> 出来的就是toString()的结果

public String toString() {
    return getClass().getName() + "@" + Integer.toHexString(hashCode());
}

用法:在子类上toString()方法重写,会出现规整的对象形式

@Override
public String toString() {
    return "Teacher{" +
            "name='" + name + '\'' +
            ", age=" + age +
            '}';
}

对象的finalize() 方法#

当对象被回收时,系统自动调用该对象的 finalize 方法。子类可以重写该方法,做一些释放资源的操作

bmw = null;
System.gc();//主动调用垃圾回收器

★封装 encapsulation#

封装三步: ① private 属性; ② 设置一个public的 set方法; ③ 设置一个public的 get方法; 《快捷键ALT + INS》


★继承 extends#

继承格式: public 子类 extends 父类 {}

继承的内存布局#

细节:#

  1. 父类非私有,子类直接访问; 父类私有通过get方法访问; 父类构造器的调用不限于直接父类!将一直往上追溯直到 Object 类(顶级父类)

  2. (重点) 子类必须先调用父类的构造器才能初始化, 没设置 默认是无参构造器父(){super(name, age, sex)}

  3. supper. 和 this. ; this是从子类开始向上查找, supper是从父类开始向上查找; 在定义时使用

  4. 构造器里面的 super() 和 this() 都只能放在构造器第一行,因此这两个方法不能共存在同一个构造器

  5. java 是单继承机制,子类最多只能继承一个父类 (想继承多个只能 A 继承 B, B 继承 C)

  6. 子类方法不能缩小父类方法的访问权限

方法重写/方法覆盖 override#

与父类的某方法,其方法名、返回类型、参数 一致构成 方法重写
注意:

  1. 重写的子类方法不能缩小父类方法的访问权限;
  2. 重写的返回类型可以是同类(Object->String之类)
  3. 方法重写override 和 方法重载overload 区别 (重载是类里面的不同方法体现:形参必须得不一样,其他必须得一样)

★多态#

是面向对象的第三大特征,多态是建立在封装和继承基础之上的, 有继承关系才能有多态


类实例的 多态体现#

class Fu {}
class Zi extends Fu {}
Fu f = new Zi();// 1. Fu f 编译类型,定义的时候就确定了,不能改变; 2. new Zi 运行类型,能改变; 3. f 能引用Fu下的所有对象,体现了多态

Fu f 能指到父类下的所有类型,实现多态
Fu f = new Zi(); 也叫向上转型,使用场景:引用多态对象
注意: 1. 此时f.name 是编译类型只能找到父类的属性,子类同名属性必须得向下转型 ((Fu) f).name
注意: 2. 此时f.getName() 是编译类型只能找到父类的定义过的方法,执行动态绑定(new 后)的方法
注意: 3. 此时f.getName() 是编译类型只能找到父类的定义过的方法,若子类有特有方法必须 向下转型 ((Fu) f).func()

动态绑定机制#

  1. 当调用对象方法的时候,该方法会和该对象的内存地址/运行类型绑定
  2. 当调用对象属性时,属性没有动态绑定机制,哪里声明,那里使用

形参的 多态体现#

方法定义的形参类型为父类类型,实参类型允许为子类类型

public Object func(People obj) { // 调用改方法时,obj可以是People下的任何子对象
    return obj;
}

多态数组的 多态体现#

People[] arr = new People[5];

arr 能装下People类下的所有对象,实现多态


继承之方法重写的 多态体现#

class People{
    public String func(){
        return "父的info";
    }
}
class Teacher extends People{
    @Override
    public String func() {
        return super.func() + "子的info";
    }
}

func()重写后能装父类和子类的方法,实现多态

posted @   1502god  阅读(23)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
-->
点击右上角即可分享
微信分享提示
主题色彩