Back
Featured image of post JavaSE 面向对象

JavaSE 面向对象

JavaSE–面向对象整合

面向对象的三条主线

  • 类和类员:属性,方法,构造器,代码块等
  • 面向对象的三大特征:封装,继承,多态
  • 其他关键字:this,super,abstract,interface,static, final,package,import

封装

封装性的体现:

  • 我们将类的属性xxx私有化(private),同时,提供公共的(public)方法来获取(getxxx)和设置(setxxx)此属性的值
  • 不对外暴露的私有方法
  • 单例模式
权限修饰符:(权限从小到大)

private , 缺省(不写) , protected , public

继承

一旦子类A继承了父类B,则子类A就获得了父类B中声明的结构(所有属性、方法等,包括封装性)

Java继承的规定

  • 单继承性:一个类只能有一个父类

  • 子父类是相对的概念

  • 子类直接继承的父类,称为:直接父类。间接继承的父类称为间接父类(java中一个子类不存在多个父类,只有间接继承,即一个子类的父类是另一个类的子类)

多态

可以理解为一个事物的多种形态

也称为对象的多态性:父类的引用指向子类的对象。 eg:

class Person{
}
class Man extends Person{
}
class Women extends Person{
}
//对象的多态性,父类的引用指向子类的对象
Person p1 = new Man();
Person p2 = new Women();

多态性的使用:虚拟方法调用

有了多态性以后,在编译的时候,只能调用父类的声明的方法,而运行时,实际执行的是子类重写父类的方法

即:编译看左边,运行看右边


多态性的使用前提:①有类的继承;②有方法的重写

多态性属于运行时行为


​ 多态小结 多态作用: 提高了代码的通用性,常称作接口重用 前提:需要存在继承或者实现关系, 有方法的重写 成员方法:

  • 编译时:要查看引用变量所声明的类中是否有所调用的方法。

  • 运行时:调用实际new的对象所属的类中的重写方法。

    成员变量:不具备多态性,只看引用变量所声明的类。


  • 如果没有多态性,则需要写很多重载的方法

  • 多态性只使用于方法,不适用于属性

构造器

  • 每一个类都有构造器
  • 构造器的作用:①创建对象;②给对象初始化(属性)

说明:

1,如果没有显式的定义类的构造器的话,则系统默认提供一个空参的构造器

2,定义构造器的格式:权限修饰符 类名(形参列表){}

public Person(){
    
}

3,一个类中可以有多个构造器,彼此构成重载

4,没有显式定义的才会有默认构造器,一旦显式的定义了构造器,系统则 不再提供空参构造器

5,一个类至少有一个构造器

6,默认构造器的权限和所在类的权限相同

属性赋值顺序:

①默认初始化

②显式初始化

③构造器中赋值

④通过“对象 . 属性”或“对象 . 方法”赋值

this关键字

  • this相当于:当前对象或当前正在创建的对象

  • 用来区分重名的属性和形参

  • 可以用来修饰:属性,方法,构造器

this 调用构造器:(根据参数列表调用)

this();   //调用空参的构造器
this(形参列表);

规定:调用构造器时,“this(形参列表)”必须声明在当前构造器的首行

构造器中不能用this调用自己,只能调其他的构造器

如果一个类中有n个构造器,则最多只能有n-1个this调用构造器,不能往回调

super关键字

  • super理解为:父类的(类似this用法)

  • super可以调用 属性、方法、构造器

  • 可以在子类的方法或构造器中,通过 super . 属性 或 super . 方法的方式,显式的调用父类中声明的属性或方法。通常情况下,习惯省略super

  • 特殊的,子类和父类定义了同名的属性时,此时若要调用父类的属性,必须使用super调用父类的

  • 父类方法被重写后,需要使用super调用父类中的被重写的方法

super调用父类构造器

super(形参列表);
  • super(形参列表)必须声明在构造器的首行
  • this(形参列表)和super(形参列表)不能同时出现
  • 默认调用super(空)
  • 在类的多个构造器中,至少有一个类的构造器是用来super(形参列表)

方法详解

  • 方法的重载
  • 可变形参的方法
  • 方法参数的值传递机制
  • 递归方法
方法重载:
  • 在同一个类中,允许存在一个以上的同名方法,只要它们的参数个数或者参数类型不同即可

  • 与返回值无关,只看参数列表且参数列表必须不同(参数个数或参数类型)

    调用时,根据方法参数列表的不同来区别

以下方法都是重载:

public void getsum(int i , int j){
    System.out.println(i + j);
}

public void getsum(double i ;double j){
    System.out.println(i + j);
}

public void getsum(String i ,int i){
    System.out.println(i + j);
}

public void getsum(int i ,String j){
    System.out.println(i + j);
}
  • 即使是参数列表顺序不同,也构成重载,根据传递参数顺序调用具体的函数

  • 跟方法的权限修饰符,返回值类型,形参变量名,方法体都无关

  • 通过对象调用方法时,如何确定某一指定方法:

    先看方法名,如果有重载,再根据参数列表判断(方法名——>参数列表)

可变个数的形参:

1.JDK5.0新增内容,调用可变个数形参时,可以传入多个参数

2.具体使用:

​ 格式:变量类型…形参变量名,eg:

public void show(String ... str){
    return 0;
}
//调用时可以同时传递多个参数
test.show("hello","world","he");
  • JDK5.0以前需要传递多个参数时,使用的是数组,因此可变形参新特性不能续数组共存(会构成重载)
//以下方法构成重载(表示的是同一个东西)
public void (String[] arr){
    
}

public void (String ... arr){
    
}

方法的形参传递机制:值传递
  • 机制:如果参数是引用数据类型,此时实参赋给形参的是实参存储数据的地址

swap(a,b);

只有参数类类型为引用数据类型(类的对象)时才能交换,eg:

class Data{
    int m;
    int n;
}
punlic static void main(String[] args){
    Data data = new Data();
    data.m = 10;
    data.n = 20;
    v.swap(data);
    System.out.println(data m , data n);
}
swap(Data data){
    int temp = data.m;
    data.m = data.n;
    data.n = temp;
}
  • 关于变量赋值:

    如果变量是基本数据类型,此时传递的是保存数据的值

    如果变量是引用数据类型,此时传递的是保存数据的地址

递归方法

方法内调用方法本身,例如,斐波那契数列,汉诺塔问题

方法的重写

override / overwrite

  1. 重写:子类继承父类以后,可以对父类中同名同参数的方法进行覆盖操作(适当改变方法体的内容)

  2. 应用:重写以后,当创建类对象以后,通过子类对象调用父类中的同名同参数的方法时,实际执行的是子类重写父类的方法

  3. 重写的规定:

    ​ 方法的声明:权限修饰符 返回值类型 方法名(形参列表){

    //方法体(不同)

    }

    约定俗称:子类中的叫重写的方法,父类中的叫被重写的方法

    ①两个方法的方法名和形参列表必须相同,方法体不同

    ②子类中的重写的方法权限修饰符不小于父类中的被重写的

    tips:子类不能重写父类中的声明为private权限的方法

    ③返回值类型

    • 父类中被重写的方法是返回值类型是void类型,则子类中返回值只能是void 类型
    • 父类中被重写的方法是返回值类型是A类型,则子类中可以是A类型或A类型的子类
    • 父类中被重写的方法是返回值类型是基本数据类型,则子类中必须是相同的基本数据类型

toString()的使用

  • 输出一个对象的引用时,实际上就是调用当前对象的toString()方法

调用父类的构造器:super.toString

?如何实现调用父类的父类的toString方法:

将根父类(父类的父类)中重写的toString方法体放在一个新的方法中,例如:

@override
public String getToString(){
    return id + name + age + salary;
}
public String toString(){
    return getToString;//return id + name + age + salary;
}

接着在子类的子类中调用 :getToString()方法

instanceof关键字

instanceof关键字的使用
多态性的弊端

有了多态性以后,内存中实际上是加载了子类所特有的属性和方法,但由于变量声明为父类类型(eg:Person p1 = new Man(); ),所以导致编译时,p1对象只能调用父类中声明的属性和方法(包括子类重写的),而不能调用子类所特有的属性和方法

向下转型

目的就是:调用子类特有的属性和方法

向下转型:使用强制类型转换符

Person p1 = new Man();
Man m1 = (Man) p1;//将声明为Person类型的对象强转为Man类型

将子类赋给父类(向上转型多态)是自动类型提升而将父类赋给子类则需要强转
  • 为了避免向下转型时出现异常,转型前使用instanceof关键字进行判断,若返回true,继续;返回false,不继续向下转型

  • a instanceof A :判断对象a是否是类A的实例,如果是,返回true;如果不是,返回false

  • 如果 a instanceof A返回true,a instanceof B 也返回true,

    其中B是A的父类

static关键字

有些属性是每个对象都共同拥有,不用给每个对象都定义,static针对的是类,不针对具体的对象,每个对象都公共的拥有同一个static变量

static关键字的使用
  • static:静态的
  • static可以修饰属性、方法、代码块、内部类

static修饰属性
  • static修饰的属性称为静态变量( 或类变量),非static修饰的属性称为实例变量
  • 可以通过类直接调用静态属性
  • 静态属性随着类的加载而加载

实例变量:我们创建了多个对象,每个对象都独立的拥有一套非静态属性。当通过其中一个对象修改非静态属性时,其他对象的此属性不会被影响

静态变量:我们创建了多个对象,这多个对象共同享有同一个静态变量。通过一个对象修改静态属性时,由于静态属性时公共的,因此其他对象再调用此静态变量时,是被修改过的


栈:局部变量

堆:new出来的结构:对象、数组

方法区:类的加载信息、静态域、常量池


static修饰方法

  • 静态方法中不能调用非静态的属性或方法(因为非静态的生命周期不够,静态方法加载完成时还没有非静态的)
  • 在静态的方法内,不能使用this、super关键字(this、super都基于当前对象)

  • 属性:开发中,当属性可以被多个对象共享,不会随着对象的改变而改变时,可以定义为static
  • 方法:工具类中的方法,习惯声明为static

包装类(Wrapper)

包装类介绍

  • 希望让八种基本数据类型具有类的特征

  • 针对八种基本数据类型定义相应的引用类型—–包装类(封装类)

基本数据类型 包装类
byte Byte
short Short
int Integer
long Long
float Float
double Double
boolean Boolean
char Character

基本数据类型、包装类之间的转换

//基本数据类型--->包装类:调用包装类的构造器
int num = 10;
Integer num = new Integer(num);

//包装类--->基本数据类型:调用xxx包装类的xxxValue()
Integer in1 = new Integer(12);
int in1 = in1.intValue();

Float f1 = new Float(12.3);
float f1 = f1.floatValue();

JDK 5.0新特性:自动装箱与自动拆箱

  • 自动装箱:
//自动实现基本数据类型--->包装类(不用调用构造器)
int num2 = 10;
Integer in1 = num2;//自动装箱
  • 自动拆箱:
//自动实现包装类--->基本数据类型(不用调用xxx.Value())
Integer in2 = new Integer();
int num3 = in2;//自动拆箱

String类与基本数据类型、包装类之间的转换

//String类型--->基本数据类型、包装类:调用包装类型的               parsexxx(String str)
String str1 = "123";
int num2 = Integer.parseInt(str1);
System.out.println(num + 2);      //125
//基本数据类型、包装类--->String类型:调用String重载的             ValueOf(Xxx xxx)
double f1 = 10.1;
String str2 = String.valueOf(f1);
System.out.println(str2 + 2);	 //10.12

抽象类与抽象方法

abstract

  • 抽象的,不实例
  • 可以修饰:类、方法

抽象类:

  • 此类不能实例化,即不能造此类的对象
  • 但一定有构造器,因为此类的子类继承后,还需要调用此父类的构造器
super(name,age);

抽象方法:

  • 没有方法体,没有大括号,只有方法的声明
  • 由于没有方法体,所以不能用对象调用,因此包含抽象方法的类一定是抽象类
  • 若子类重写了父类的所有抽象方法后,才能实例化;若子类没有重写父类的抽象的方法,则子类必须是抽象类

abstract使用注意点:

  • 不能用来修饰属性、构造器、代码块等结构
  • 不能用来修饰私有方法(子类必须重写抽象父类的方法,但private不能被重写
  • 不能用来修饰静态方法、final方法、final类

抽象类的匿名子类:

Person p = new Person(){
    //子类的重写的方法
    @override
    ...
};

单例设计模式

让一个类只能存在一个对象实例,并且该类只提供一个获得其对象实例的方法,如果我们要让类在虚拟机中只能产生一个对象,首先要将类的构造器访问权限设置为private,这样就不能用new操作符在类的外部产生类的对象了。由于在类的外部无法得到类的对象,只能调用该类的静态get方法以返回类内部创建的对象。

单例设计模式主要分四步:

1.将类的构造器设置为私有

2.类内部创建类的对象(私有、静态)

3.提供共有的静态方法从类外获取类的对象

4.步骤二中对象也必须声明为静态的

单例设计模式主要有:饿汉式懒汉式

饿汉式:提前创建好对象,安全但占用多余空间

懒汉式:对象在需要用的时候再创建,节省空间但不够安全

异常

java.lang.Throwable:

​ >java.lang.Error:一般不编写针对代码处理

​ >java.lang.Exception:异常一般指这个,可以进行异常的处理

Exception分为:

  • 编译时异常(checked):

    IOException —>FileNotFoundException

    ClassNotFoundException

  • 运行时异常(unchecked, RuntimeException):

    NullPointerException

    ArrayIntexOutOfBoundsException

    ClassCastException

    NumberFormatException

    InputMismatchException

    ArithmetiException

异常处理

抓抛模型

过程一"抛":程序在正常执行的过程中,一旦出现异常,就会在异常处生成一个异常类的对象,并将此对象抛出。

一旦抛出对象以后,其后的代码不再执行

过程二:“抓”:可以理解为异常的处理方式:

​ ①try—catch—finally

​ ②throws

 * //try-catch-finally的使用
 * 
 * try{
 * 		//可能出现异常的代码
 * 
 * }catch(异常类型1 变量名1){
 * 		//处理异常的方式1
 * }catch(异常类型2 变量名2){
 * 		//处理异常的方式2
 * }catch(异常类型3 变量名3){
 * 		//处理异常的方式3
 * }
 * ....
 * finally{
 * 		//一定会执行的代码
 * }

异常处理方式二: throws + 异常类型

  1. “throws + 异常类型” 写在方法的声明处。指明此方法执行时,可能会抛出的异常类型

    一旦当方法体执行时,出现异常,仍会在异常代码处生成一个异常类的对象,此对象满足throws后异常类常时,就会被抛出。异常代码后续的代码不再执行。

  2. 体会:try—catch—finally:真正地将异常处理了

    ​ throws:只是将异常抛给了方法的调用者,并没有处理


    子类重写方法异常的规则:

    子类重写的方法中throws的异常类型只能小于等于父类中的异常类型,子类中也可以没有


    开发中如何选择?(try—catch—finally or throws )

    • 如果父类中被重写的方法没有throws方式处理异常,则子类中也不能用throws,此时如果子类中如果有异常,必须使用try-catch-finally处理。
    • 执行的方法A中,先后又调用了另外的几个方法,这几个方法是递进关系执行的。建议让这几个方法使用throws处理,而执行的方法A可以考虑使用try-catch-finally处理

    手动抛出异常

    throw new 异常对象名();

    异常对象需要继承于异常体系,一般写 Exception 或 RuntimeException

    也可以自定义,但必须继承于异常体系

承认自己的无知 , 乃是开启智慧的大门
comments powered by Disqus
Built with Hugo
Theme Stack designed by Jimmy