Java面向对象基础、进阶与高级

文章目录

  • 一、面向对象基础
    • 1、面向对象思想
      • 1.1 概述
      • 1.2 三大思想
      • 1.3 三大特征
        • 1.3.1 封装
        • 1.3.2 继承
        • 1.3.3 多态
          • 对象的多态性
          • 方法的多态性
    • 2、类与对象
      • 2.1 两者关系
      • 2.2 类、属性、方法定义
        • 2.2.1 类定义
        • 2.2.2 属性定义
        • 2.2.3 方法定义
      • 2.3 对象的创建与使用
    • 3、创建对象内存分析
      • 3.1 栈
      • 3.2 堆
      • 3.3 方法区
      • 3.4 PC寄存器
      • 3.5 本地方法栈
    • 4、 构造方法(构造器)
      • 4.1 概述与格式
      • 4.2 构造方法的设计
    • 5、 重载
      • 5.1 方法的重载@overload
      • 5.2 构造方法的重载
    • 6、匿名对象
  • 二、面向对象进阶
    • 1、封装private
      • 1.1 特点
      • 1.2 意义
      • 1.3 举例
    • 2、this
    • 3、static
      • 3.1 tips
    • 4、代码块
      • 4.1 普通代码块
      • 4.2 构造代码块
      • 4.3 静态代码块
      • 4.4 同步代码块
    • 5、 包
      • 5.1 作用
      • 5.2 使用规则
      • 5.3 import关键字
    • 6、 权限修饰符
    • 7、 final关键字
      • 7.1 修饰属性、变量
      • 7.2 修饰类
      • 7.3 修饰方法
    • 8、main方法详解
    • 9、单例设计模式
      • 9.1 实现步骤
      • 9.2 两种实现方式
        • 9.2.1 懒汉式
        • 9.2.2 饿汉式
  • 三、面向对象高级
    • 1、抽象类abstract
      • 1.1 抽象类
      • 1.2 抽象方法
      • 1.3 tips
      • 1.4 抽象类区别于普通类
    • 2、接口
      • 2.1 定义
      • 2.2 接口的实现implemets
      • 2.3 接口的继承exrends
      • 2.4 面向接口编程思想
      • 2.5 接口中全局常量和抽象方法的简写
      • 2.6 接口和抽象类的区别
    • 3、多态
      • 3.1多态的体现
        • 3.1.1 对象的多态性
        • 3.1.2 方法的多态性
      • 3.2 多态的使用
      • 3.3 instanceof
    • 4、 object类
      • 4.1 object的多态
      • 4.2 toString
      • 4.3 equals
    • 5、内部类
      • 5.1 成员内部类
      • 5.2 局部内部类
      • 5.3 匿名内部类
      • 5.4 静态内部类
    • 6、包装类
      • 6.1 装箱和拆箱操作
      • 6.2 字符串转换
    • 7、可变参数
    • 8、递归
  • [异常处理]
    • 1、 什么是异常?
    • 2、 异常体系结构
    • 3、处理异常的方法
      • 3.1 try-catch
        • 3.1.1 基本语法
        • 3.1.2 处理过程
        • 3.1.3 处理多异常
          • 3.1.3.1 注意点
          • 3.1.3.2 格式
            • 格式一
            • 格式二
            • 格式三
      • 3.2 throws关键字
        • 3.2.1 基本语法
        • 3.2.2 处理过程
    • 4、throw关键字(区别于throws)
    • 5、自定义异常类
      • 5.1 Exception与RuntimeExcepion的区别
        • 5.1.1 Exception
        • 5.1.2 RuntimeException
    • 6、finally关键字
    • 7、常见的有关finally的面试题
      • Q1
      • Q2
      • Q3
      • Q4
      • Q5

一、面向对象基础

1、面向对象思想

1.1 概述

  • 面向对象是相对于面向过程来讲的,指的是把相关的数据和方法组织为一个整体来看待。
  • 面向过程→面向对象思想层面的转变:
    面向过程关注的是执行的过程,面向对象关注的是具备功能的对象
    面向过程到面向对象,是程序员思想上从执行者到指挥者的转变。

1.2 三大思想

  • 面向对象思想从概念上讲分为以下三种:OOA、OOD、OOP
    OOA:面向对象分析(Object Oriented Analysis)
    OOD:面向对象设计(Object Oriented Design)
    OOP:面向对象程序(Object Oriented Programming

1.3 三大特征

1.3.1 封装

全部内容对外不可见(信息隐藏,用类进行封装)

  • 特点
    对内:结构完整,可自我管理,自我平衡,高度集中
    对外:功能明确,接口单一,各种环境独立工作
  • 意义
    保护、防止代码及数据被无意中破坏
    保护成员属性,不让类意外的程序直接访问和修改
    仅对外公开访问方法,隐藏对象属性和实现细节
1.3.2 继承

功能继承下来继续发展,即子类继承父类非私有的方法和属性

  • tips:
    新类必须在已有类的基础上进行构造。
    单根继承,父类只有一个
    允许多重继承(a继承b,b继承c),但是不允许多继承(a继承b和c)
    每个类都有父类:Object(根类)
  • super关键字
    访问父类的构造方法、属性、方法
    调用super构造方法的代码必须放在子构造方法的第一行(自动创建父类对象)
    【区别于this关键字,this指的是当前对象】
  • 重写
    参数列表、返回类型必须完全与被重写方法相同
    访问权限不能比父类中被重写的方法的访问权限更低(比如父类为public,子类不能为protected)
    父类的成员方法只能被子类重写
    static和private不能被重写,但是能再次被声明
  • 【区别于重载】
    重写与重载的区别
重写@override 重载@overload
子类父类中 一个类中
参数列表必须相同 参数列表必须不同
返回值类型必须一致 与返回值类型无关
子类访问权限必须不能小于父类的访问权限 与访问权限无关
可以减少或删除(异常范围更小,但不能抛出异常) 与异常处理无关
1.3.3 多态

对象的多种表现形式(多种体现形态)

对象的多态性

在类中有子类、父类之分,子类为父类的一种形态

方法的多态性

方法的多态性即相同的方法有多种形态

  • 重载:一个类中方法的多态性体现
  • 重写(继承):子类父类中方法的多态性体现

2、类与对象

2.1 两者关系

  • 类表示一个共性的产物,是一个综合的特征
    对象是一个个性的产物,是一个个体的特征
  • 类必须通过对象才可以使用,对象的所有操作都在类中定义。
  • 类由属性和方法组成:
    属性:就相当于人的一个个的特征
    方法:就相当于人的一个个的行为

2.2 类、属性、方法定义

2.2.1 类定义

class 类名称{
成员属性;
成员方法;
}

2.2.2 属性定义

属性定义: 数据类型 属性名;
属性定义并赋值:数据类型 属性名 = 初始化值;

2.2.3 方法定义

权限修饰符 返回值类型 方法名(形式参数列表){
//方法体
return 返回值;//return 用来结束方法
}

2.3 对象的创建与使用

一个类要想真正的进行操作,则必须依靠对象。

  • 对象的定义

对象的定义:
类名称 对象名称 = new 类名称() ;

  • 如果要想访问类中的属性或方法(方法的定义),则可以依靠以下的语法形式

访问类中的属性: 对象.属性 ;
调用类中的方法: 对象.方法(实际参数列表);

3、创建对象内存分析

3.1 栈

  • 存储基本数据类型的数据以及引用数据类型的引用
  • 内存通过栈指针来创建与释放空间(有具体大小,限制了灵活性)

例如:
int a =10;
Person p = new Person();
10存储在栈内存中 , 第二句代码创建的对象的引用( p )存在栈内存中

3.2 堆

  • 存放的是类的对象
  • Java所有类的对象都是通过new关键字创建(new关键字, 是指告诉JVM , 需要明确的去创建一个新的对象 , 去开辟一块新的堆内存空间
  • 堆内存优点在于我们创建对象时 , 不必关注堆内存中需要开辟的存储空间以及内存占用时长
  • 堆内存中内存的释放是由GC(垃圾回收器)完成的
  • GC回收堆内存的规则:
    当栈内存中不存在此对象的引用时,则视其为垃圾 , 等待GC回收。

3.3 方法区

  • 存放的是
    类信息
    静态的变量
    常量
    成员方法
  • 方法区中包含了一个特殊的区域 ( 常量池 )(存储的是使用static修饰的成员)

3.4 PC寄存器

  • PC寄存器保存的是当前正在执行的JVM指令的地址
  • 在Java程序中, 每个线程启动时, 都会创建一个PC寄存器

3.5 本地方法栈

保存本地(native)方法的地址

4、 构造方法(构造器)

4.1 概述与格式

构造方法(也叫构造函数):创建对象时自动调用,用于对象初始化

类名 对象引用名 = new 构造方法();
Employee emp =new Employee();

  • tips:
    ①名称与类必须相同
    ② 没有返回类型说明
    ③ 每个类至少存在一个构造方法(没有则自动生成,但只有方法体没有内容)

4.2 构造方法的设计

当类中有非常量成员变量时,建议提供两个版本的构造方法,一个是无参构造方法,一个是全属性做参数的构造方法
当类中所有成员变量都是常量或者没有成员变量时,建议不提供任何版本的构造。

5、 重载

5.1 方法的重载@overload

方法的重载:在同一个类中同一个名字表示不同的方法

  • 方法名必须相同(同一类中定义的同名方法)
  • 方法的参数必须不同(形参的个数、类型、顺序中至少一种不同)
  • 返回的类型可以不同,与返回值类型无关(可以相同也可以不同,因此仅返回值不同则不构成重载)

5.2 构造方法的重载

  • 一个类, 可以存在多个构造方法 :
    参数列表的长度或类型不同即可完成构造方法的重载
  • 建议构造两个构造方法:无参全参
  • 构造方法的重载 ,可以让我们在不同的创建对象的需求下, 调用不同的方法来完成对象的初始化
  • 面试题
    重写(override)与重载(overload)的区别
重写override 重载overload
发生位置 子类父类中 同一个类中
参数列表限制 必须相同 必须不同
返回值类型 必须一致 与返回值无关
访问权限 子类访问权限≥父类 与访问权限无关
异常处理 可以减少or删除(使异常范围更小,但不能抛出新异常) 与异常无关

6、匿名对象

  • 没名字
  • 栈中无内容,只出现在堆中
  • 只用一次,用完就自动回收(因为没有任何的对象引用)

例:

  • 非匿名

Math m = new Math();
int num = m.sum(1,2);

  • 匿名

new Math();
int num = new Math().sum(1,2);

二、面向对象进阶

1、封装private

1.1 特点

全部内容对外不可见(信息隐藏,用类进行封装)
对内:结构完整,可自我管理,自我平衡,高度集中
对外:功能明确,接口单一,各种环境独立工作

1.2 意义

保护、防止代码及数据被无意中破坏
保护成员属性,不让类意外的程序直接访问和修改
仅对外公开访问方法,隐藏对象属性和实现细节(建议对所有的属性进行封装,并为其提供setter及getter方法进行设置和取得操作)

1.3 举例

  • 封装前
class Person{
	String name ; // 表示姓名
	int age ; // 表示年龄
	
	void tell(){
	System.out.println("姓名:" + name + ";年龄:" + age) ;
	}
};
public class Demo{
	public static void main(String args[]){
	Person p = new Person() ;
	p.name = "张三" ;
	p.age = -30 ;
	p.tell() ;
	}
};
  • 封装后
class Person{
	private String name ; // 表示姓名
	private int age ; // 表示年龄
	
	void tell(){
	System.out.println("姓名:" + getName() + ";年龄:" + getAge()) ;
	}
	
	public void setName(String str){
		name = str ;
	}
	public void setAge(int a){
		if(a > 0 && a < 150)
		age = a ;
	}
	public String getName(){
		return name ;
	}
	public int getAge(){
		return age ;
	}
};
public class Demo{
	public static void main(String args[]){
		Person p = new Person() ;
		p.setName("张三") ;
		p.setAge(-30) ;
		p.tell() ;
}

2、this

  • 表示当前对象
  • 可以调用类中的属性类中的方法or构造方法
    tips:在一个构造方法中调用另一个构造方法时,调用的方法写在第一行

例:

Person(){
	this("张三"-30);//必须写在第一行
	system.out.println("创建对象!");
}

3、static

  • 表示**“静态”**的意思,可以用来修饰成员变量、成员方法(、静态代码块、静态内部类)
  • 主要作用在于创建独立于具体对象的域的变量或者方法
    简单理解:
    【简单概括:在类加载时,加载并初始化,属于类,只有一份
    …被static关键字修饰的方法或者变量不需要依赖于对象来进行访问,只要类被加载了,就可以通过类名去进行访问
    …不会因为对象的多次创建,而在内存中建立多份数据,只有一份。

3.1 tips

  • 静态成员在类加载时,加载并初始化
  • 无论一个类存在多少个对象,静态的属性在内存中永远只有一份(可以理解为所有对象公用)
  • 在访问时,静态不能访问非静态,非静态可以访问静态
    (静态成员在类加载时就已经加载并初始化,而当非静态成员能被访问时表明对象已经创建,因此类一定加载,此时静态成员一定存在)
  • 静态修饰的方法被调用时,有可能对象未创建
    (当类是静态时)

4、代码块

4.1 普通代码块

编写在顺序执行的流程中出现的代码块

4.2 构造代码块

在类中成员代码块

  • 随着对象的每次创建,执行一次,且在构造方法之前
  • 无论用户调用哪个构造方法创建对象,构造代码块都执行
    每次对象创建时执行, 执行在构造方法之前。】

例:

Class Person{
	//构造代码块
	{
		System.out.prntln("创建对象!");
	}
	//构造方法
	person(){};
	Person(String name,int age){
		this.name = name;
		thia.age = age;
	}
}

4.3 静态代码块

构造代码块前加上Static(在类中使用static修饰的成员代码块)
随着类加载,静态代码快执行
由于类只加载一次,因此静态代码块只执行一次

4.4 同步代码块

后续多线程技术中学习(待补充)

  • 面试题
    构造方法 与 构造代码块 以及 静态代码块 的执行顺序:
    静态代码块 --> 构造代码块 --> 构造方法
    【类先加载到内存,再创建对象。静态代码块在类加载到内存时执行。构造代码块和构造方法都在创建对象时执行,构造代码块执行在构造方法之前】

5、 包

  • 把功能相似或相关的类或接口组织在同一个包中,方便类的查找和使用。
  • 如同文件夹,不同的包中的类的名字是可以相同的,当同时调用两个不同包中相同类名的类时,应该加上包名加以区别。包可以避免名字冲突
  • 包也限定了访问权限,拥有包访问权限的类才能访问某个包中的类。

(即以下三个作用)

5.1 作用

  • 方便
  • 实现命名空间管理
  • 访问权限设置(public、private、protected…),拥有包访问权限的类才能访问某个包中的类,使用import导入包

5.2 使用规则

  • 包中java文件的定义:
    在.java文件的首部, 必须编写类所属哪个包, 格式:package 包名;
  • 包的定义:
    通常由多个单词组成, 所有单词的字母小写, 单词与单词之间使用.隔开 ,一般命名为“com.公司名.项目名.模块名…”。
  • 包名可以有层次,为树形目录的存储方式,以小数点分隔,全是小写。
  • 如果一个源文件中没有使用包声明,那么其中的类、函数、注释等将被放在一个无名的包(unnamed package)中

规范由来:
由于Java面向对象的特性,每名Java开发人员都可以编写属于自己的Java Package,为了保障每个JavaPackage命名的唯一性,在最新的Java编程规范中,要求开发人员在自己定义的包名前加上唯一的前缀。由于互联网上的域名称是不会重复的,所以多数开发人员采用自己公司在互联网上的域名称作为自己程序包的唯一前缀。例如:com.java.xxx

5.3 import关键字

  • import 包名.类名;

6、 权限修饰符

修饰符 子类 其他包
public
protected
default(默认)
private(封装)

7、 final关键字

7.1 修饰属性、变量

  • 修饰后成为常量,无法进行再次赋值
    若修饰局部变量,只能赋值一次(可以先声明后赋值)
    若修饰成员属性,必须在声明时赋值

局部变量和成员属性的区别:

局部变量 成员属性
定义的位置 方法
内存中的位置 存储在栈内存的方法中 存储在堆内存的对象中
声明周期 随着方法的运行而出现,随着方法的出栈而消失 随着对象的出现而出现,随着对象的消失而消失
初始化不同 没有默认初始化值,必须初始化后才可以使用 因为在堆内存中,所以有默认的初始化值
  • 全局常量定义: public static final

public:权限最大
static:表示它属于类的,随的类的加载而存在(如果是非static表示属于对象,只有建立对象时才有它)
final:不能被修改

7.2 修饰类

  • 被final修饰的类不能被继承

7.3 修饰方法

  • 不能被子类重写

8、main方法详解

public static void main(String args[])

  • public:公共的内容,可以被所有操作所调用
  • static:方法是静态的,可以由类名称直接调用。java StaticDemo09
  • void:没有任何的返回值操作
  • main:系统规定好的方法名称。如果main写错了或没有,会报错:NoSuchMethodError: main
  • String[] args:字符串数组,接收参数的

9、单例设计模式

  • 属于创建型模式
  • 保证程序在内存中只有一个对象存在(被程序所共享)
  • 这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。

9.1 实现步骤

  • 保证一个类只有一个实例
    …实现方式:构造方法私有化
  • 必须要自己创建这个实例
    …实现方式:在本类中维护一个本类对象(私有,静态)
  • 单例必须给所有其他对象提供这一实例
    …实现方式:对外提供公共的访问方式(getInstance方法,静态)

9.2 两种实现方式

9.2.1 懒汉式

随着类的加载在内存中对象为null,当调用 getInstance 方法时才创建对象(延迟加载)
优点:第一次调用才初始化,避免内存浪费。
缺点:必须加锁 synchronized 才能保证单例,但加锁会影响效率。

class Single1{
	private Single1(){};
	private static Single1 s1 = null;
	public static Single1 getInstance(){//判断系统是否已经有这个单例,如果有则返回,如果没有则创建。
		if(s1 == null){
			s1 = new Single1();
		}
		return s1;
	}
}
9.2.2 饿汉式

随着类的加载直接创建对象(推荐开发中使用)
优点:没有加锁,执行效率会提高。
缺点:类加载时就初始化,浪费内存。

class Single2{
    //让构造函数为 private,这样该类就不会被实例化
	private Single2(){}
	
    //创建 Single2的一个对象
	private static Single2 s2 = new Single2();
	
	//获取唯一可用的对象
	public static Single2 getInstance(){
		return s2;
	}
	
	void print(){
		System.out.println("Hello World!");
	}
}
  • 从 single类获取唯一的对象
public class SingleTest {
   public static void main(String[] args) {
      //不合法的构造函数,编译时会产生错误:构造函数 Single2() 是不可见的
      //即Single2 object = new Single2();
 
      //获取唯一可用的对象
      Single2 s = Single2.getInstance();
 
      //显示消息
      s.printn();
   }
}

三、面向对象高级

1、抽象类abstract

1.1 抽象类

  • 抽象类必须使用abstract声明
  • 抽象类不能产生一个对象(不能new一个对象)
  • 抽象类可以没有抽象方法

格式:
abstract class 类名{ // 抽象类
}

1.2 抽象方法

  • 只声明而未实现的方法(未实现指的是:没有“{}”方法体)
  • 必须写在抽象类或者接口中。
  • 必须使用abstract关键字声明。
  • 抽象方法只有方法头没有方法体

格式:
abstract class 类名{ // 抽象类
public abstract void 方法名() ; // 抽象方法,只声明而未实现
}

1.3 tips

  • 抽象类不能被实例化,即:不能直接使用关键字new完成。
  • 一个抽象类必须被子类所继承,被继承的子类(如果不是抽象类)则必须重写抽象类中的全部抽象方法
  • 不能使用final关键字(final不能有子类)

=

  • 面试题
    抽象类能否有构造方法?
    能有构造方法(不能被我们创建,但能被JVM创建)
    而且子类对象实例化的时候的流程与普通类的继承是一样的,都是要先调用父类中的构造方法(默认是无参的),之后再调用子类自己的构造方法。

1.4 抽象类区别于普通类

  • 必须用public(默认)或procted 修饰
    (如果为private修饰,子类则无法继承,也就无法实现其抽象方法)
  • 不可以使用new关键字创建对象, 但是在子类创建对象时, 抽象父类会被JVM实例化
  • 如果一个子类继承抽象类,那么必须实现其所有的抽象方法(attention:抽象类中的普通方法可以直接使用,抽象方法必须全被实现),如果有未实现的抽象方法,那么子类也必须定义为abstract类

2、接口

  • 全部方法都是抽象方法
  • 全部属性都是全局常量
  • 如果一个接口要想使用,必须依靠子类。 子类(如果不是抽象类的话)要实现接口中的所有抽象方法。

2.1 定义

interface 接口名称{
全局常量 ;
抽象方法 ;
}

2.2 接口的实现implemets

  • 基本格式:

class 子类 implements 父接口1,父接口2…{
}

  • 如果一个类即要实现接口,又要继承抽象类:

class 子类 extends 父类 implements 父接口1,父接口2…{
}

2.3 接口的继承exrends

接口因为都是抽象部分, 不存在具体的实现, 所以允许多继承
例如:

interface C extends A,B{
}

2.4 面向接口编程思想

是接口定义(规范,约束)与实现(名实分离的原则)的分离。

  • 优点:
    1、降低程序的耦合性
    2、易于程序的扩展
    3、有利于程序的维护

2.5 接口中全局常量和抽象方法的简写

接口都是由全局常量抽象方法组成 , 所以接口中的成员定义可以简写:
1、全局常量编写时, 可以省略public static final 关键字,例如:(public static final )String INFO = “内容” ;
2、抽象方法编写时, 可以省略 public abstract 关键字, 例如:(public abstract) void print() ;

2.6 接口和抽象类的区别

接口 抽象类
被类实现 被子类继承
只能声明抽象方法 可以声明抽象方法,也可以声明非抽象方法
定义的变量只能是公共的静态常量 变量为普通变量
使用实现来使用,可以多实现 使用继承来使用,无法多继承
不能有构造方法 可以有构造方法
不允许包含static方法(接口中的都要被子类重写,静态方法不允许被重写) 可以包含static方法

3、多态

  • 对象的多种表现形式,(多种体现形态)

3.1多态的体现

3.1.1 对象的多态性

在类中有子类、父类之分,子类为父类的一种形态

3.1.2 方法的多态性

方法的多态性即相同的方法有多种形态

  • 重载:一个类中方法的多态性体现
  • 重写(继承):子类父类中方法的多态性体现

3.2 多态的使用

类似于基本数据类型的转换:

  • 向上转型:子类实例→父类实例
    格式:父类 父类对象 = 子类实例 ;
  • 向下转型:父类实例→子类实例
    格式:子类 子类对象 = (子类)父类实例 ;

Java面向对象基础、进阶与高级_第1张图片

3.3 instanceof

  • 判断某个对象是否是指定类的实例
  • 格式:
    实例化对象 instanceof 类 //此操作返回boolean类型的数据
    例:
public static void say(Person p){
	if (p instanceof Student){//判断对象p是否为学生类
		Student s = (Student)p;
		s.say();
	}else {
		System.out.println("必须传入学生形态!");
	}
}

4、 object类

  • Object类是基类,是所有类的父类(基类)
  • 如果一个类没有明确的继承某一个具体的类,则将默认继承Object

    例如我们定义一个类:
    public class Person{
    }
    其实它被使用时 是这样的:
    public class Person extends Object{
    }

4.1 object的多态

使用Object可以接收任意的引用数据类型
例:

public static void main(String[] args){
	String text = "123";
	say(text);
	int a = 10;
	say(a);
	say("123");
}
public static void say(Object o){//多态的体现
	System.out.println(o);
}

4.2 toString

  • 默认为字符串,返回对象的内存地址(对象实例的类名称@对象的哈希码的无符号十六进制)
  • 建议重写Object中的toString方法

4.3 equals

  • 等于
    当且仅当x和y引用同一对象( x == y具有值true )时,此方法返回true
  • ==比的是内存地址

equals方法重写时的五个特性:

自反性 :对于任何非空的参考值x , x.equals(x)应该返回true 。
对称性 :对于任何非空引用值x和y , x.equals(y)应该返回true当且仅当y.equals(x)返回true 。
传递性 :对于任何非空引用值x ,y和z ,如果x.equals(y)回报true并且y.equals(z)返回true,x.equals(z)应该返回true 。
一致性 :对于任何非空引用值x和y ,多次调用x.equals(y)始终返回true或始终返回false ,前提是未修改对象上的equals比较中使用的信息。
非空性 :对于任何非空的参考值x , x.equals(null)应该返回false 。

5、内部类

  • 将一个类定义在另一个类里面或者一个方法里面
  • 分类
    成员内部类
    局部内部类
    匿名内部类
    静态内部类
  • (内部类其实不怎么用)

5.1 成员内部类

  • class中再class一个
class Outer {
	private double x = 0;
	public Outer(double x) {
		this.x = x;
	}
	
	 //内部类
	class Inner {
		public void say() {
			System.out.println("x=" + x);
		}
	}
}
  • 特点
    成员内部类可以无条件访问外部类的所有成员属性和成员方法(包括private成员和静态成员)。
    当成员内部类拥有和外部类同名的成员变量或者方法时(重名),默认访问成员内部类的成员。如果要访问外部类的同名成员,则:
    外部类.this.成员变量
    外部类.this.成员方法

在外部使用成员内部类:

Outter o = new Outter();
Outter.Inner i = o.new Inner();

5.2 局部内部类

  • 定义在方法or作用域里面的类(范围有限)
  • 像方法里面的一个局部变量,不能有public、protected、private以及static修饰符
  • 只能访问final型的局部变量(1.8之后定义变量final可省略,不用明显标出来)
class Person{
	public Person() {}
}

class Man{
	public Man(){}
	public People getPerson(){
		//局部内部类
		class Student extends People{ 
			int age =0;
		}
		return new Student();
	}
}
  • 面试题
    为什么局部内部类只能访问final类型的局部变量?
    内部类会单独被编译成字节码文件,为了保证文件中备份的变量与外部变量的值保持一致,系统限制了其值的更改

5.3 匿名内部类

  • 属于局部内部类的一种
  • 必须要继承一个父类或者实现一个接口
  • 没有class关键字(匿名内部类是直接使用new来生成一个对象的引用,这个引用是隐式的)

构造方法:

new 父类构造器(参数列表)| 实现接口()
{
//匿名内部类的类体部分
}

Java面向对象基础、进阶与高级_第2张图片

  • tips
    ①必须是继承一个类或者实现一个接口(继承、实现二选一)
    ②不能定义构造函数
    ③不能存在任何的静态成员变量or方法
    ④为局部内部类,所以局部内部类的所有限制同样对匿名内部类生效(定义在方法or作用域里面、不能有public、protected、private以及static修饰符、只能访问final型的局部变量)
    ⑤不能是抽象的,必须要实现继承的类或者实现的接口的所有抽象方法

5.4 静态内部类

  • class里面再class一个,加上static
  • 不需要依赖于外部类对象
  • 不能访问外部的非static资源(成员变量或者方法)
    静态只能访问静态

格式:

class Outter {
	public Outter() {}
	static class Inner {
		public Inner() {}
	}
}

在外部使用静态内部类:

//区别于成员内部类
//由于静态,因此可以直接用 外部类.内部类 创建对象
Outter.Inner i = new Outter.Inner();

6、包装类

基本数据类型 占用内存(字节) 包装类
字节型byte 1 Byte
短整数型short 2 Short
整数型int 4 Integer
长整数型long 8 Long
浮点型float 4 Float
双精度型double 8 Double
字符型char 2 Character
布尔型boolean 1 Boolean
  • Number子类:Byte,Short.Integer,Long,Float,Double
  • Object子类:Character,Boolean

6.1 装箱和拆箱操作

  • 装箱:将基本数据类型变为包装类
  • 拆箱:将包装类变为基本数据类型

拆箱:(父类Number中定义了如下方法)

方法 描述
public byte byteValue() Byte→byte
public abstract double doubleValue() Double→double
public abstract float floatValue() Float→float
public abstract int intValue() Integer→int
public abstract long longValue() Long→long
public short shortValue() Short→short

装箱:

  • 在JDK1.4之前,直接使用各个包装类的构造方法。例如:
int temp = 10 ; // 基本数据类型
Integer x = new Integer(temp) ; //装箱
int a = x.intValue();//拆箱
  • JDK1.5新增了自动装箱和自动拆箱,而且可以直接通过包装类进行四则运算和自增自建操作。例如:
Float f = 10.3f ; // 自动装箱
float x = f ; // 自动拆箱
System.out.println(f * f) ; // 直接利用包装类完成
System.out.println(x * x) ; // 直接利用包装类完成

6.2 字符串转换

  • 使用包装类,将一个字符串变为指定的基本数据类型
  • 在接收输入时用的比较多

String→int:public static int parseInt(String s)
String→Float:public static float parseFloat(String s)
String→boolean:public static boolean parseBoolean(String s)

7、可变参数

  • 可以根据需要自动传入任意个数的参数
  • 可变参数只能出现在参数列表的最后
  • 格式:

返回值类型 方法名称(数据类型…参数名称){
//参数在方法内部 , 以数组的形式来接收
}

8、递归

  • 在方法的定义中使用方法自身
    Java面向对象基础、进阶与高级_第3张图片

[异常处理]

异常处理、finally关键字以及finally常见面试题

  • 明确什么是异常(重点)
  • 便是常见的异常及含义(熟悉)
  • 理解异常产生的原理(了解)
  • 处理异常(重点)
  • 能自定义异常类型(熟悉)

1、 什么是异常?

在程序中导致程序中断运行的一种指令流。

2、 异常体系结构

异常指的是Exception , Exception类, 在Java中存在一个父类Throwable(可能的抛出)
Throwable存在两个子类:
1.Error:表示的是错误,是JVM发出的错误操作,只能尽量避免,无法用代码处理。
2.Exception:一般表示所有程序中的错误,所以一般在程序中将进行try…catch的处理。
Java面向对象基础、进阶与高级_第4张图片

3、处理异常的方法

3.1 try-catch

3.1.1 基本语法

try{
// 有可能发生异常的代码段
}catch(异常类型1 对象名1){
// 异常的处理操作
}catch(异常类型2 对象名2){
// 异常的处理操作
} …
finally{
// 异常的统一出口
}

  • tips
    try中出问题,catch进行补救
    可以没有catch部分,有异常则会抛出
    不论是否异常都会执行finally(相当于释放)
3.1.2 处理过程
  • 一旦产生异常,则系统会自动产生一个异常类的实例化对象。
  • 若异常在try语句中,则自动找到匹配的catch语句执行
    若异常不在try语句中,则抛出(抛给调用该异常的方法)
  • 所有的catch根据方法的参数匹配异常类的实例化对象,如果匹配成功,则表示由此catch进行处理。
3.1.3 处理多异常
3.1.3.1 注意点
  • 捕获更细的异常放在前面。
  • 如果为了方便,则可以将所有的异常都使用Exception进行捕获。
3.1.3.2 格式
格式一
  • 基本格式

try{
// 有可能发生异常的代码段
}catch(异常类型1 对象名1){
// 异常的处理操作
}catch(异常类型2 对象名2){
// 异常的处理操作
} …
finally{
// 异常的统一出口
}

格式二
  • 了解即可

try{
// 有可能发生异常的代码段
}catch(异常类型1 | 异常类型2 对象名){
// 异常的处理操作
}
finally{
// 异常的统一出口
}

格式三
  • 常用格式
  • RuntimeException体现了多态
  • Exception亦可体现

try{
// 有可能发生异常的代码段
}catch(RuntimeException 对象名){
// 异常的处理操作
}
finally{
// 异常的统一出口
}

3.2 throws关键字

  • 表示方法中不处理异常,而交给调用处处理
3.2.1 基本语法

返回值 方法名() throws Exception{

}

3.2.2 处理过程
  • 发生了异常,JVM根据异常的情况创建了一个异常对象,里面包含了异常的信息
  • main未处理,自动将异常抛给main的调用者JVM
  • JVM对异常信息进行响应(将异常信息显示到控制台,中断处理
public class demo {
    public static void main(String[] args) {
        int[] arr = new int[10];
        System.out.println(arr[11]);
        System.out.println("程序正常结束");
    }
}

4、throw关键字(区别于throws)

  • 很少很少用
  • 人为抛出的一个异常
//代码实例
public void setAge(int age){
	if(age<0 || age>180){
		RuntimeExcetion e = new RuntimeException("不合理");
		throw e;//人为抛出异常
	}else{
		this.age = age;
	}
}

5、自定义异常类

编写一个类, extends [Exception / RuntimeExcepion],并重写一参构造方法

5.1 Exception与RuntimeExcepion的区别

5.1.1 Exception

定义方法时必须声明所有可能会抛出的exception

5.1.2 RuntimeException
  • 它是Exception的子类。是那些可能在JVM正常运行期间抛出的异常的超类。可能在执行方法期间抛出但未被捕获的RuntimeException 的任何子类都无需在 throws 子句中进行声明
  • 运行时异常,不需要try-catch或throws 机制去处理异常,异常发生由JVM进行处理,当然也可以处理。

6、finally关键字

在进行异常的处理之后,在异常的处理格式中还有一个finally语句,那么此语句将作为异常的统一出口,不管是否产生
了异常,最终都要执行此段代码。

7、常见的有关finally的面试题

Q1

  • Q:finally在xxx情况下是否会执行?
    A:finally只有在程序被关闭的情况下才不会执行,否则必然执行

Q2

  • Q:try-catch-finally 中哪个部分可以省略?
    A:catch和finally可以省略其中一个, catch和finally不能同时省略
    注意:格式上允许省略catch块, 但是发生异常时就不会捕获异常了,我们在开发中也不会这样去写代码.

Q3

  • Q:在程序中,如果前面return了,finally语句块还会继续执行吗?
    A:finally中的代码块会执行。(由Q1可知,程序并没有关闭,必然执行)
try{
	...
	return;//程序到这里是否已经结束?并没有
}catch(...){
	...
}finally{
	System.out.println("执行finally");
}

执行流程:

  1. 先计算返回值, 并将返回值存储起来等待返回
  2. 执行finally代码块
  3. 将之前存储的返回值, 返回出去;
    需注意:
    1.返回值是在finally运算之前就确定了,并且缓存了,不管finally对该值做任何的改变,返回的值都不会改变
    2.finally代码中不建议包含return,因为程序会在上述的流程中提前退出,也就是说返回的值是try或catch中的值
    3.如果在try或catch中停止了JVM(程序被关闭),则finally不会执行.【例如停电, 或通过“ System.exit(0); ”代码退出JVM:】

Q4

  • Q:以下代码块中finally代码块会执行吗?
    A:不执行,"System.exit(Status:0);"是唯一可以使finally不执行的代码
try{
	int a = 10;
	int b = 0;
	System.out.print(a/b);
}catch(Exception e){
	System.exit(Status:0);//Status可选值:0、1、2、3,0表示正常退出
}finally{
	System.out.println("finally代码块执行");
}

Q5

  • Q:运行以下代码后,return 中的值分别是多少?
Public Static int demo(){
	int a = 10;
	try{
		return a;
	}caatch(Exception e){
		return null;
	}finally{
		a = 20;
	}
}
Person p == neww Person();
try{
	p.age = 18;
	return p;
}catchh(Exception e){
	return null;
}finally{
	p.age = 28;
}

第一个代码块中,return中a的值为10
第二个代码块中,return中p的age的值为28
Java面向对象基础、进阶与高级_第5张图片

基本数据类型备份的是值,引用数据类型备份的是地址。注意数据类型的区分。

你可能感兴趣的:(JavaEE,java)