2021-03-14Java大数据Week2


前言

第三章-面向对象

第2节 面向对象基础

  1. 面向对象基础

1.1 面向对象思想

1.1.1. 概述

	面向对象(Object Oriented)是软件开发方法. 面向对象的概念和应用已超越了程序设计和软件开发, 是一种对现实世界理解和抽象的方法, 是计算机编程技术发展到一定阶段后的产物.
	面向对象是相对于面向过程来讲的, 指的是,把 相关刷机和方法组织为一个整体 来看待, 从更高的层次来及逆行系统建模, 更贴近事物的自然运行模式.
面向过程到面向对象思想层面的转变:
	面向过程关注的是执行的过程, 面向对象关注的是具备功能的对象.
	面向过程到面向对象, 是程序员思想上 从执行者到指挥者的转变.
	
	此概念如果直接去理解的话可能会比较抽象, 因为大多数缺少对原始的面向过程的开发语言的了解, 下面举一个例子

1.1.2. 举一个例子

我们通过生活中的一个脑经急转弯, 来理解这个概念.
	问:
		把大象装进冰箱, 需要分几步?
		
	回答:
		面向过程回答:
			3步: 1把冰箱打开,	2把大象装进去, 3把冰箱门关上
		面向对象回答:
			2步: 1招一个能操作冰箱的工人(对象), 2指挥工人装大象
	思考:
		如果问题改成: 把100只大象依次装进冰箱, 共分为几步?
		面向过程的回答: 此处需要省略N字...
		面向对象的回答还是2步:
		1招一个能操作冰箱的工人(对象), 2指挥工人把大象依次装进去.
	
	
	结论:
		从上述的例子中, 我们发现面向过程很死板, 是很难适应变化的, 而面向对象更灵活, 可复用性更高.

1.1.3. 例子:好吃, 再举一个

我们再描述一个生活的场景:
	场景:
		当我们独自生活时,	我们经常纠结一日三餐怎么吃.
		
		面向过程:
			每天亲力亲为: 买菜 - 做饭 - 吃饭 - 洗碗 的过程.
		面向对象:
			招聘一个保姆, 每天等吃即可.
			
	场景升级:
		假设你是一个富豪,	拥有一座占地3000亩地的庄园, 步再是只关注吃饭问题, 还有花草树木修剪, 泳池维护清洗, 卫生打扫, 洗衣做饭......
		面向过程:
			此处省略看着就累的N字.
		面向对象:
			招聘一个管家, 然后让管家招聘 园丁, 泳池维护工, 保姆等等.
			
			
	结论:
		从上述的例子中, 我们发现面向过程, 我们需要关注很繁琐的过程.
		而面向对象不用关注具体的细节, 更关注的是统筹架构的问题.
		
		其实我们进行大型应用开发时, 就如上述的例子一样, 如果我们写程序只关注过程的话, 代码量达到一定层次以后, 就很难再编写下去.
		如果采用面向对象的思想来设计编写程序, 我们就可以只关注结果.

1.1.4. 三大思想

面向对象思想从概念上讲分为以下三种: OOA OOO OOP

	OOA:面向对象分析 (Object Oriented Analysis)
	OOO:面向对象设计 (Object Oriented Design)
	OOP:面向对象程序 (Object Oriented Programming)

1.1.5. 三大特征

封装性: 所有的内容对外部不可见
继承性: 将其它的功能基础下来继续发展
多态性: 方法的重载本身就是一个多态性的体现

1.2 类与对象

1.2.1 两者关系

	类表示一个共性的产物, 是一个综合的特征, 而对象, 是一个个性的产物, 是一个个体的特征.(类似生活中的图纸与实物的概念.)
	类必须通过对象才可以使用, 对象的所有操作都在类中定义.
	类由属性和方法组成:
		* 属性: 就相当于人的一个个的特征
		* 方法: 就相当于人的一个个的行为, 例如: 说话,吃饭,唱歌,睡觉

1.2.2 类的定义格式

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

1.2.3 属性与方法

属性定义格式:
	数据类型 属性名;
属性定义并赋值的格式:
	数据类型 属性名 = 初始化值;
	
方法定义格式:
	权限修饰符	返回值类型 方法名(形式参数列表){
		//方法体
		return 返回值;
	}

1.2.4 对象的创建与使用

一个类要想真正的进行操作, 则必须依靠对象, 对象的定义格式如下:
	类名称 对象名称 = new 类名称() ;
	
如果想要访问类中的属性或方法(方法定义), 则可通过以下的语法形式:

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

1.3 创建对象内存分析

1.3.1 栈

Java栈的区域很小, 大概2m左右, 特点是存取的速度特别快
栈存储的特点是, 先进后出

存储速度快的原因:
	栈内存, 通过 "栈指针" 来创建空间与释放空间!
	指针向下移动, 会创建新的内存, 向上移动, 会释放这些内存!
	这种方式速度特别快, 仅次于PC寄存器!
	
	但是这种移动的方式, 必须要明确移动的大小与范围,
	明确大小与范围是为了方便指针的移动, 这是一个对于数据存储的限制, 存储的数据大小是固定的, 影响了程序的灵活性~
	
	所以我们把更大部分的数据 存储到了"堆内存"中
	
堆内存存储的是:
	基本数据类型的数据 以及 引用数据类型的引用!
    例如:
    int a = 10;
    Person p = new Person();
    10存储在堆内存中, 第二句代码创建的对象的引用存储在栈内存中

1.3.2 堆

存放的是类的对象.
Java是一个纯面向对象的语言, 限制了对象的创建方式:
	所有类的对象都是通过new关键字创建
	
new关键字, 是指告诉JVM, 需要明确的去创建一个新的对象, 去开辟一块新的堆内存空间;

堆内存与栈内存不同, 优点在于我们创建对象时, 不必关注堆内存中需要开辟多少存储空间, 也不需要关注内存占用时长!

堆内存中内存的释放是由GC("垃圾回收器")完成的
栈内存中内存的释放是由JVM完成的

垃圾回收器 回收堆内存的规则:
	当栈内存中不存在此对象的引用时, 则视其为垃圾, 等待垃圾回收器回收!

例如:
	Person p0 = new Person();
	Person p1 = p0;			//p1,p0 指向堆内存地址相同
	Person p2 = new Person();

1.3.3 方法区

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

1.3.4 PC寄存器

PC寄存器保存的是 当前正在执行的 JVM指令的 地址!

在Java程序中, 每个线程启动时, 都会创建一个PC寄存器!

1.3.5 本地方法找

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

1.4 构造方法(构造器)

1.4.1 回顾对象创建

Person p = new Person();

在右侧Person后面出现的小括号, 其实就是在调用构造方法!

1.4.2 概述

作用:
	用于对象初始化.
执行时机:
	在创建对象时, 自动调用
特点:
	所有的Java类中都会至少存在一个构造方法
	如果一个类中没有明确的编写构造方法, 则编译器会自动生成一个午餐的构造方法, 构造方法中没有任何的代码!
	
	如果自行编写了任意一个构造器, 则编译器不会再自动生成无参的构造方法!

1.4.3 定义格式

定义的格式:
	与普通方法基本相同, 区别在于: 方法名称必须与类名相同, 没有返回值类型的声明!
	
案例:
	public class Demo3{
		public static void main(String[] args){
			Person p = new Person();
			p = new Person();
			p = new Person();
			p = new Person();
		}
	}
	class Person{
		public Person(){
			System.out.println("对象创建时, 此方法调用");
		}
	}

1.4.4 构造方法设计

建议自定义无参构造方法, 不要堆编译器形成依赖, 避免错误发生.

当类中有非常量成员变量时, 建议提供两个版本的构造方法, 一个是无参构造方法, 一个是全属性作参数的构造方法.

当类中所有成员变量都是常量或者没有成员变量时, 建议不提供任何版本的构造.

1.5 方法的重载

同一个类中,方法名称相同,	参数类型或参数长度不同, 可以完成方法的重载! 方法的重载与返回值无关!

方法的重载, 可以让我们在不同的需求下, 通过传递不同的参数调用方法来完成具体的功能.

1.6 构造方法的重载

一个类, 可以存在多个构造方法:

参数列表的长度或类型不同即可完成构造方法的重载~

构造方法的重载, 可以让我们在不同的创建对象的需求下, 调用不同的方法来完成对象的初始化!

1.7 匿名对象

没有对象名称的对象 就是匿名对象.

匿名对象只能使用依次, 因为没有任何的对象引用, 所以将成为垃圾, 等待被GC回收.

只使用一次的对象可以通过匿名对象的方式完成 ,这一点在以后的开发中将经常使用到.

第3节-面向对象进阶

2.面向对象进阶

2.1 封装 private

我们观察如下代码:
	class Person{
        private String name;	//表示姓名
        private int age;	//表示年龄
        void tell(){
            System.out.println("姓名: "+name+"; 年龄: "+age);
        }
    };

	public class Demo{
        public static void main(String[] args){
            Person per = new Person();
            per.name = "张三";
            per.age = 30;
            per.tell();
        }
    };


以上操作代码并没有出现语法错误, 但是出现了逻辑错误 (年龄-30)
    
在开发中, 为了避免出现逻辑错误,	我们建议对所有属性进行封装, 并为其提供setter及getter方法进行设置和取得操作.
    
    
    
 修改代码如下:
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(){
        retrun name;
    }
    
    public int getAge(){
        return age;
    }
};

public class Demo10{
    public static void main(String[] args){
        
        Person per = new Person();
        per.setName("张三");
        per.setAge(-30);
        per.tell();
    }
}

2.2 this

在Java基础中, this关键字是一个最重要的概念. 使用this关键字可以完成以下的操作:
	* 调用类中 的属性
	* 调用类中 的方法或构造方法
	* 表示 当前对象

2.3 static

  • 概述
static 表示"静态"的意思, 可以用来修饰 成员变量和成员方法 (后续还会学习 静态代码块和静态内部类).

static 的主要作用在于创建独立于具体对象的域变量或方法

简单理解:
	被static关键字修饰的方法或者变量 不需要依赖于对象来进行访问, 只要累被加载了, 就可以通过"类名"去进行访问.
	并且不会因为对象的多次创建 而在内存中建立多份数据.

*重点:静态相当于原本图纸存在的, 而非静态相当于在图纸上另外发现问题的基础上加的

1. 静态变量 在类加载时加载并初始化.
2. 无论一个类存在多个个对象, 静态的属性, 永远在内存中只有一份 (可以理解为所有对象公用).
3. 在访问时:	静态不能访问非静态,	非静态可以访问静态!

2.4 代码块

普通代码块:
	在执行流程中 出现的 代码块,	我们称其为 普通代码块.
	
构造代码块:
	在类中的成员代码块,	我们称其为 构造代码块,	在每次对象创建时执行, 执行在构造方法之前.
	
静态代码块:
	在类中使用static修饰的成员代码块,	我们称其为静态代码块,	在类加载时执行, 每次程序启动到关闭, 只会执行一次的代码块.
	
同步代码块:
	在后续多线程技术中学习.
面试题:
	构造方法	与	构造代码块	以及	静态代码块的执行顺序:
	
		静态代码块 --> 构造代码块 --> 构造方法

2.5 包

2.5.1 包介绍

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

2.5.2 包的使用规则

->	包中java文件的定义:
		在.java文件的首部,	必须编写类所属哪个包,	格式:
		package 包名:
		
		
->	包的定义:
		通常由多个单词组成,	所有单词的字母小写,	单词与单词之间使用 . 隔开, 一般命名为"com.公司名.项目名.模块名....".
		
	规范由来:
		由于Java面向对象的特性, 每名Java开发人员都可以编写属于自己的Java package, 为了保障每个Java Package命名的 唯一性, 在最新的Java编程规范中, 要求开发人员在自己定义的包名前加上唯一的前缀. 由于互联网上的域名称是不会重复的, 所以多数开发人员采用自己公司在互联网上的域名称作为自己程序包的唯一前缀. 
		例如:
			com.java.xxx

2.5.3 import关键字

import 包名.类名;

2.6 权限修饰符

在这里插入图片描述

2.7 main 方法详解

main()方法一直写到了今天:
public static void main(String[] args)
	以上的各个参数的含义如下:
		*public: 表示公共的内容, 可以被所有操作所调用
		*static: 表示方法是静态的, 可以由类名称直接调用, java StaticDemo
		*void: 表示没有任何的返回值操作
		*main: 系统规定好的方法名称. 如果main写错了或没有, 会报错:No such Method Error: main
		*String[] args: 字符串数组, 接收参数的
		
		
public class StaticDemo{
	public static void main(String[] args){
		for (int i=0;i<args.length;i++) {
			System.out.println("args[i]");
		}
	}
};

] 所有的参数在执行类的时候以空格进行分割.
Java StaticDemo 1 2 3 4 5 6 7

	但是, 如果现在我要输入的是以下几种参数"hello world","hello vince","hello mjw".
	
	因为以空格分割, 所以以上的三组参数会当做六组参数输入, 那么此时如果要想完成有空格的内输入,
则参数需要使用""""括起来.

Java StaticDemo "hello world" "hellow vince" "hello mjw"

2.8 单例设计模式

单例设计模式 是我们学习的第一个设计模式, 也是比较重要的一个设计模式, 单例设计模式会伴随着你的开发生涯, 不管你是初级程序员, 还是以后晋级到高级程序员, 你都会接触到 单例设计模式, 今天,我们就学习单例设计模式的  两种实现方法.

单例设计模式: 保证程序在内存中只有一个对象存在 (被成员所共享)

单例设计模式的两种实现方式:

一. 懒汉式: 随着类的加载 在内存中对象为null, 当调用 getInstance 方法时才创建对象 (延迟加载)
二. 饿汉式: 随着类的加载直接创建对象 (推荐开发中使用)

单例设计模式的实现步骤:

1. 保证一个类 只有一个实例, 实现方式: 构造方法私有化
2. 必须要自己创建这个实例, 实现方式: 在本类中维护一个本类对象 (私有,静态)
3. 必须向整个程序提供这个实例, 实现方法: 对外提供公有的访问方式 (getInstance方法, 静态)


懒汉式实现如下:
class Single{
	private Single(){}
	
	private static Single s1 = null;
	public static Single getInstance(){
		if (s1 == null) {
			s1 = new Single();
		}
		return s1;
	}
}

饿汉式实现如下:
class Single2{
	private Single2(){}
	
	private static Single2 s = new Single2();
	
	public static Single getInstance(){
		return s;
	}
	
	void print(){
		System.out.println("Hello World!");
	}
}

第4节-面向对象高级

1. 抽象类

概念

抽象类必须使用abstract class声明

一个抽象类中可以没有抽象方法. 抽象方法必须写在抽象类或者接口中.

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

抽象方法

只声明 而未实现 的方法 称为抽象方法 (为实现指定的: 没有"{}"方法体), 抽象方法必须使用abstract关键字声明

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

不能被实例化

在抽象类的使用中有几个原则:
	* 抽象类本身是 不能直接进行实例化操作的, 即: 不能直接使用关键字new完成.
	* 一个抽象类必须被子类所继承, 被继承的子类 (如果不是抽象类) 则必须重写(覆写)抽象类中的全部抽象方法.

常见问题

1.	抽象类能否使用final声明?

	不能, 因为final属修饰的类是 "不能有子类的",	而抽象类必须有子类才有意义, 所以不能.
	
2.	抽象类能否有构造方法?
	
	能有构造方法, 而且子类对象实例化的时候的流程 与普通类的继承是一样的, 都是要先调用父类中的构造方法 (默认是无参的), 之后再调用子类自己的构造方法.

抽象类和普通类的区别

1. 抽象类必须用public 或 protected 修饰(如果为private修饰, 那么字类则无法继承, 也就无法实现其抽象方法). 默认缺省为 public.
2. 抽象类不可以使用new关键字创建对象, 但是在子类创建对象时, 抽象父类也会被JVM实例化.

3. 如果一个子类继承抽象类, 那么必须实现其  所有的抽象方法, 如果有未实现的抽象方法, 那么子类也必须定义为 abstract类

2. 接口

概念

如果一个类中的全部方法都是抽象方法, 全部属性都是全局变量, 那么此时就可以将这个类定义成一个接口.

定义格式:
	interface	接口名称{
		全局变量 ;
		抽象方法 ;
	}

面向接口编程思想

这种思想是 接口定义(规范, 约束) 与实现 (名实分离的原则) 的分离.

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

全局常量和抽象方法的简写

因为接口本身都是 由全局常量 和 抽象方法组成,	所以接口中的成员定义可以简写:

	1. 全局常量编写时,	可以省略public static final关键字, 例如:
		public static final String INFO = "内容";
	
	2. 抽象方法编写时,	可以省略 public abstract
		public abstract void print();
		简写后:
		void print();

接口的实现 implements

接口可以多实现:
格式:
	class 子类 implements 父接口1,父接口2,... {
	
	}
	
以上的代码称为 接口的实现, 那么如果一个类 即类要实现接口, 又要继承抽象类的话,则按照以下格式编写即可:

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

接口继承

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

注意:

如果一个接口要想使用, 必须依靠子类, 子类 (如果不是抽象类的话), 要实现接口中的所有抽象方法.

接口和抽象类的区别

1. 抽象类要被子类继承, 接口要被类实现.
2. 接口只能声明抽象方法, 抽象类中可以声明抽象方法, 也可以写非抽象方法.
3. 接口里定义的变量只能是 公共的静态的常量, 抽象类中的变量是普通变量.
4. 抽象类使用继承来使用, 无法多继承,	接口使用实现来使用,	可以多实现
5. 抽象类中可以包含static方法, 但是接口中不允许 (静态方法不呢被子类重写, 因此接口中不能声明静态方法).
6. 接口不能有构造方法, 但是抽象类可以有

3. 多态

概念

多态: 就是对象的多种表现形式. (多种体现形态)

多态的体现

对象的多态性, 从概念上非常好理解, 在类中有子类和父类之份, 子类就是父类的一种形态, 对象多态就从此而来.

ps : 方法的重载 和 重写 也是多态的一种, 不过是方法的多态 (相同方法名的多种形态).

	重载: 一个类中方法的多态性体现
	重写: 子父类中方法的多态体现.

多态 的使用 : 对象的类型转换

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

* 向上转型: 将子类实例 变为 父类实例
		!~ 格式: 父类 父类对象 = 子类实例;
* 向下转型: 将父类实例变为子类实例
		!~ 格式: 子类 子类对象 = (子类) 父类实例;

4. instanceof

作用:
	判断某个对象是否是指定类的实例, 则可以使用instanceof 关键字
	
格式:
	实例化对象 instanceof 类		//此操作返回boolean类型的数据

5. Object类

概念

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

例如我们定义一个类:
public class Person{

}

其实它被使用时 是这样的:
public class Person extends Object{

}

Object的多态

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

toString

建议重写Object中的toString方法. 此方法的作用: 返回对象的字符串表示形式.
	Object的toString方法, 返回对象的内存地址

equals

建议重写Object中的 equals(Object obj)方法, 此方法的作用: 指示某个其它对象是否"等于"此对象.

	Oject的equals方法: 实现了对象上最具区别的可能等价关系; 也就是说, 对于任何非空引用值x和y,
当且仅当x和y引用同一对象 ( x == y具有值true) 时,此方法返回true.

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

	自反性: 对于任何非空的参考值x , x.equals(x)应该返回 true.
	对称性: 对于任何非空引用值x和y , x.equals(x)应该返回true 当且仅当 y.equals(x)汇报 true.
	传递性: 对于任何非空引用值x , y 和 z, 如果 x.equals(y)回报 true个 y.equals(z) 汇报 true,
然后 x.equals(x) 应该返回 true.

	一致性: 对于任何非空引用值 x 和 y, 多次调用 x.equals(y) 始终返回 true 或始终返回 false,前提是未修改对象上的 equals 比较中使用的信息.
	非空性: 对于任何非空的参考值 x , x.equals(null)应该返回 false.

6. 内部类

概念

在 Java中, 可以将一个类定义在另一个类里面 或者一个方法里面, 这样的类称为内部类.
	广泛意义上的内部类一般来说包括这四种:
		1. 成员内部类
		2. 局部内部类
		3. 匿名内部类
		4. 静态内部类

成员内部类

成员内部类是最普通的内部类, 它的定义为 位于另一个类的内部, 形如下面的形式:

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	outter = new Outter();
	Outter.Inner inner = outter.new Inner();

局部内部类

局部内部类是定义在一个方法 或者 一个作用域 里面的类, 它和成员内部类的区别在于 局部内部类的访问仅限于	"方法内或者该作用域内".

例如:
	class Person{
		public Person(){
		
		}
	}
	
	class Man{
		public Main(){
		
		}
		
		public People getPerson(){
			class Student extend People{	//局部内部类
				int age = 0;
			}
			return new Student();
		}
	}
注意: 局部内部类 就像是 方法里面的一个局部变量一样, 是不能有 public,protected,private以及 static 修饰符的.

匿名内部类

匿名内部类由于没有名字,	所以它的创建方式有点儿奇怪. 创建格式如下:

	new 父类构造器 (参数列表) | 实现接口 ()
	{
		//匿名内部类的 类体部分
	}
	
	在这里我们看到使用匿名内部类 我们必须要继承一个父类或者实现一个接口, 当然也仅能 只继承一个父类 或者实现一个接口. 同时它也是 没有class 关键字, 这是因为匿名内部类 是直接使用 new来生成一个对象的引用. 当然这个引用是隐式的.

注意:

在使用匿名内部类的过程中, 我们需要注意如下几点:

	1. 使用匿名内部类时, 我们必须是继承一个类或者实现一个接口, 但是两者不可兼得, 同时也之只能继承一个类 或者实现一个接口.
	
	2. 匿名内部类中是 不能定义构造函数的.
	
	3. 匿名内部类中 不能存在 任何的静态成员变量和静态方法.
	
	4. 匿名内部类为 局部内部类, 所以 局部内部类的所有限制 同样对匿名内部类生效.
	
	5. 匿名内部类 不能是抽象的, 它必须要实现继承的类或者实现的接口的所有抽象方法.
	
	6. 只能访问final型的局部变量

静态内部类

静态内部类 也是定义在另外一个类里面的类, 只不过在类的前面多了一个关键字 static.
静态内部类是 不需要依赖于外部类对象的, 这点和类的静态成员属性有点类似, 并且它不能使用外部类的非static成员变量或者方法.
格式:
public class Test{
	public static void main(String[] args){
		Outter.Inner inner = new Outter.Inner();
	}
}

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

7. 包装类

概述

在Java中有一个设计的原则 "一切皆对象" , 那么这样一来Java中的一些基本的数据类型, 就完全不符合于这种设计思想,	
因为Java中的八种基本类型 并不是引用数据类型, 所以Java中为了解决这种问题,引入了八种基本数据类的包装类.

在这里插入图片描述

以上的八种包装类, 可以将基本数据类型按照类的形式进行操作.

	但是, 以上的八种包装类也是分为两种大的类型:
	* Number: Integer Short Long Double Float Byte都是Number的子类表示是一个数字.
	* Object: Character Boolean都是Object的直接子类.

装箱和拆箱操作

以下以	Integer和Float 为例进行操作

将一个基本数据类型 变为 包装类, 那么这样的操作称为 装箱操作.
将一个包装类 变为 一个基本数据类型, 这样的操作称为拆箱操作.

因为所有的数值型的包装类 都是Number的子类, Number的类中 定义了如下的操作方法, 
以下的全部方法都是进行拆箱的操作.

在这里插入图片描述

装箱操作:

在JDK1.4之前, 如果要想装箱, 直接使用各个包装类的构造方法即可, 例如:
	int temp = 10;	//基本数据类型
	Integer x = new Integer(temp);	//将基本数据类型变为包装类
	
在JDK1.5, Java新增了自动装箱和自动拆箱, 而且可以直接通过包装类进行四则运算和自增自建操作.例如:

	Float f = 10.3f;	//自动装箱
	float x = f; 	//自动拆箱
	
	System.out.println( f*f );	//直接利用包装类完成
	System.out.println(	x*x );	//直接利用包装类完成

字符串转换

使用包装类还有一个很优秀的地方在于:	可以将一个字符串变为指定的基本数据类型, 此点一般在接收输入数据上使用较多.
在Integer类中提供了以下的操作方法:
	public static int parseInt(String s): 将String变为int型数据.

在Float类中提供了以下的操作方法:
	public static float parseFloat(String s): 将String变为Float型数据.
	
在Boolean类中提供了以下操作方法:
	public static boolean parseBoolean(String s): 将String变为boolean
	...
	...

8. 可变参数

一个方法中定义完了参数, 则在调用的时候必须传入与其一一对应的参数, 但是在JDK 1.5 之后提供了新的功能, 可以根据需要自动传入任意个数的参数.

语法:
	返回值类型 方法名称(数据类型...参数名称){
		//参数在方法内部	,	以数组的形式来接收
	}
	
注意:
	可变参数只能出现在参数列表的最后.

9. 递归

递归,	在数据与计算机科学中, 是指在方法的定义中使用方法自身. 
也就是说: 递归算法是一种直接或者间接调用自身方法的算法.

递归流程图如下:

在这里插入图片描述

第5节-IDEA安装

第6节-异常处理

异常处理

目标

1. 明确什么是异常 (重点)
2. 能辨识出常见的异常及其含义. (熟悉+)
3. 理解异常产生的原理 (了解)
4. 能处理异常 (重点)
5. 能够自定义异常类型(熟悉)

什么是异常?

异常是 在程序中导致程序中断运行的一种 指令流.

例如, 限制有如下的操作代码:

public class ExceptionDemo{
	public static void main(String[] args){
		int i = 10;
		int j =0;
		System.out.println("=================== 计算开始 ==============");
		int temp = i/j; //进行除法运算
		System.out.println("temp = "+temp);
		System.out.println("=================== 计算结束 ==============");
	}
};

运算结果:
============= 计算开始 ============= Exception in thread "main" java.lang.ArithmeticException: / by zero at ExceptionDemo01.main(ExceptionDemo01.java:6)
    
    
   以上的代码在"int temp = i/j;"位置处产生了异常, 一旦产生异常之后,
    异常之后的语句将不再执行了, 所以现在的程序并没有正确的执行完毕之后就退出了.
    
    那么, 为了保证程序出现异常之后仍然是 可以正确执行完毕, 要采用异常的处理机制.

处理异常

如果要想对异常进行处理, 则必须采用标准的处理格式, 处理格式语法如下:

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

try + catch的处理流程

1.	一旦产生异常, 则系统会自动产生一个异常类的实例化对象.
2.	那么, 此时如果异常发生在try语句, 则会自动找到匹配的catch 语句执行,如果没有在try语句中, 
则会将异常抛出.
3. 所有的catch根据方法的参数匹配异常类的实例化对象, 如果匹配成功, 则表示由此catch进行处理.

在这里插入图片描述

在这里插入图片描述

finally

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

异常体系结构

异常指的是 Exception, Exception类, 在Java中存在一个父类Throwable (可能的抛出)
Throwable存在两个子类:

	1. Error: 表示的是错误, 是JVM发出的错误操作, 只能尽量避免, 无法用代码处理.
	2. Exception: 一般表示所有程序中的错误, 所以一般在程序中将进行 try-catch 的处理.

在这里插入图片描述

多异常捕获的注意点:

	1. 捕获更粗的异常不能放在捕获更细的异常之前.
	2. 如果为了方便, 则可以将所有的异常都使用Exception 进行捕获.
特殊的多异常捕获写法:
catch (异常类型1 | 异常类型2 对象名){
	//表示此块用于处理异常类型1 和 异常类型2 的异常信息
}

throws关键字

在程序中异常基本处理已经掌握了,但是随异常一起的还有一个称为throws关键字, 此关键字主要在方法的声明上使用, 表示方法中不处理异常, 而交给调用处理.

格式:
	返回值 方法名称() throws Exception{
	
	}

throw关键字

	throw关键字表示在程序中人为的抛出一个异常, 因为从异常处理机制来看, 所有的异常一旦产生之后,实际上抛出的就是一个异常类的实例化对象, 那么此对象也可以由throw直接抛出.
	
	代码:	throw new Exception("抛着玩的. ");

RuntimeException与Exception的区别

注意观察如下方法的源码:
	Integer类:	public static int parseInt(String text) throws NumberFormatException
	
	此方法抛出了异常, 但是使用时却不需要进行try...catch 捕获处理, 原因:
	
	因为NumberFormatException并不是Exception的直接子类, 而是 RuntimeException的子类, 
	只要是RuntimeException的子类, 则表示程序在操作的时候可以不必使用try...catch进行处理, 
	如果有异常发生, 则由JVM进行处理. 当然, 也可以通过try catch处理.

自定义异常了解

编写一个类,	继承Exception, 并重写一参构造方法 即可完成自定义受检异常类型.

编写一个类, 继承RuntimeException, 并重写一参构造方法 即可完成自定义运行时 异常类型.

例如:
	class MyException extends Exception{ //继承Exception, 表示一个自定义异常类
		public MyException(String msg){
			super(msg);		//调用Exception中有一个参数的构造
		}
	};
	
	自定义异常可以做很多事情, 例如:
	class MyException extends Exception{
		public MyException(String msg){
			super(msg);
			//在这里给维护人员发短信或者邮件, 告知程序出现了bug.
		}
	}

异常处理常见面试题

1. try-catch-finally 中哪个部分可以省略?: catchfinally可以省略其中一个,	catchfinally不能同时省略

	注意:格式上允许省略catch, 但是发生异常时就不会捕获异常了, 我们在开发中也不会这样去写代码.
	
2. try-catch-finally, 如果 catchreturn, finally还会执行吗?: finally中的代码会执行

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

第7节-章节总结

在这里插入图片描述

总结

第三章第2节演示
https://blog.csdn.net/qq_43058317/article/details/114553760?spm=1001.2014.3001.5501
第三章第3节演示
https://blog.csdn.net/qq_43058317/article/details/114596824?spm=1001.2014.3001.5501
第三章第4节演示
https://blog.csdn.net/qq_43058317/article/details/114659647?spm=1001.2014.3001.5501
第三章第5节演示
https://blog.csdn.net/qq_43058317/article/details/114700934?spm=1001.2014.3001.5501
第三章第6节演示

第三章习题

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

低调的小哥哥

你的关注就是我为你服务的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值