一、初识面向对象
面向对象
:编程使用的一种编程思路,编程思想面向对象和面向过程比较
:都是编程思想,面向过程是面向对象的基础,面向对象是基于面向过程的。
面向过程
:更强调解决问题的基本步骤,强调问题的解决方式,更强调的是方法。 面向对象:更强调解决问题的主体,更强调谁来解决这个问题,更强调的是数据,更强调的是对象,更强调的是谁拥有数据和操作数据的权力。
例子:面向过程:拿盆子,盆子水,洗衣粉,放衣服,搓一搓,揉一揉,刷一刷,晾干 面向对象:洗衣机面向对象好处
:
(1)更符合人类的思想习惯
(2)复杂的问题简单化
(3)由执行者变成了指挥者面向对象的特征
:
封装
继承
多态- 面向对象是面向过程更高层次的编程思想、面向过程是面向对象的基础。面向对象基于面向过程。
- 面向过程&面向对象
二、对方法的提高
(不理解,说明对象和内存还不理解,也可以跳过先看内存和对象就理解呢!)
break与return得区别
break:跳出switch,结束循环!
return: 结束方法,返回一个结果(这个结果为空也可以是其它得类型)!
(1)创建Student类
public class Student {
//静态 static
public static void say(){
System.out.println("学生在说话");
}
//非静态
public void hi(){
System.out.println("hihihi");
}
}
(2)创建类Static_Method来调用Student
public class Static_Method {
public static void main(String[] args) {
//static和类一起加载
//静态
Student.say();
//非静态
Student student = new Student();
student.hi();
}
}
运行结果为:
(3)值传递
public class Zhi_ChuanDi {
//值传递
public static void main(String[] args) {
int a = 1;
System.out.println(a);
Zhi_ChuanDi.change(a);
System.out.println(a);
}
//返回值为空
public static void change(int a){
a = 10;
}
}
运行结果
(4)引用传递
public class YinYong_ChuanDi {
//引用传递 本质还是值传递
public static void main(String[] args) {
Person person = new Person();
System.out.println(person.name);
YinYong_ChuanDi.change(person);
System.out.println(person.name);
}
public static void change(Person person){
person.name = "Daniel";//person是一个对象指向--------------> Person person = new Person();这是一个具体的人,可以改变属性!
}
}
class Person{
String name;
}
运行结果为:
三、对象的创建分析
- 类:类型,对具体事物的一个抽象认识,是抽象出来的结果,其实就是一个概念
抽象:抽取事物中,像的相同的相似的内容出来,在人脑中形成一个概念- 对象:事物的具体体现。
(1)先创建学生类
//学生类
public class Student {
//属性: 字段
String name;//null
int age;//0
//静态方法
public static void say(){
System.out.println("学生在说话");
}
//非静态
public void hi(){
System.out.println("hihihi");
}
public void study(){
System.out.println(this.name+"在学习");
}
}
(2)创建抽象类
public class Application_Daniel {
public static void main(String[] args) {
//类:抽象的,实例化
//类实例化后返回一个自己的对象
//student对象就是一个Student类的具体实例
Student stu = new Student();
stu.name = "Wendy";
int age = 18;
Student st = new Student();
st.name = "Kendra";
st.age = 14;
System.out.println(st.name);
System.out.println(st.age);
System.out.println(stu.name);
System.out.println(stu.age);
stu.study();
}
}
运行结果为:
4.有无参构造
(1)创建Person类
public class Person {
//一个类即使什么都不写,它也会存在一个方法
//显示的定义构造器
String name;
int age;
//1.使用new关键字,本质是在调用构造器
//2.用来初始化值
public Person(){
this.name ="Kendra";
}
//有参构造:一旦定义了有参构造,无参就必须显示定义
public Person(String name){
this.name = name;
}
/**
* 构造器:
* 1.和类名相同
* 2.没有返回值
* 作用:
* 1.new 本质在调用构造方法
* 2.初始化对象的值
* 注意点:
* 1.定义有参构造之后,如果想使用无参构造,显示的定义一个无参的构造
*
* Alt+Insert
*/
}
(2)创建抽象Application类
//一个项目应该只存在一个main方法
public class Application {
public static void main(String[] args) {
//实例化一个对象
Person person = new Person();
person.name ="Daniel";
System.out.println(person.name);
}
}
运行结果显示:
5.类对象的内存理解
(1)创建一个Pet类
public class Pet {
String name;
int age;
public void shout(){
System.out.println("叫了一声");
}
}
(2)创建抽象类加载
public class PetApplication {
public static void main(String[] args) {
Pet dog = new Pet();
dog.name="旺财";
dog.age=3;
dog.shout();
System.out.println(dog.name);
Pet cat = new Pet();
cat.name="猫咪";
cat.age=2;
cat.shout();
System.out.println(cat.name);
}
}
运行结果为:
(3)内存分析
🌻🌻温故而知新🌻🌻
- 类与对象
- 类是一个模板:抽象,对象是一个具体得实例
- 方法
- 定义,调用!
- 对象得引用
- 引用类型: 基本类型(8)
- 对象是通过引用来操作得: 栈------> 堆
- 属性: 字段Field 成员变量
- 默认初始化
– 数字: 0 0.0
– char : u0000
– boolean:false
– 引用: null- 修饰符 属性类型 属性名 = 属性值!
- 对象得创建和使用
- 必须使用new 关键字创造对象,构造器 Person daniel = new Person();
- 对象的属性: daniel.name
- 对象的方法: daniel.sleep()
- 类:
- 静态的属性 属性
- 动态的行为 方法
封装,继承,多态 👇🏾👇🏾
四、面向对象三大特性
4.1 封装
(1)创建Student类
//private 私有的
public class Student {
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
if(age >= 120 || age <= 0){
this.age = 3;
}else{
this.age = age;
}
}
}
(2)创建抽象类
/**
* 封装:
* 1.提高程序的安全性,保护数据
* 2.隐藏代码的实现细节
* 3.统一接口
* 4.系统可维护增加了
*/
//判断一个方法相同:Daniel给你教两个方法:
//(1)看方法名是否相同
//(2)看参数列表是否一致
public class Student_Application {
public static void main(String[] args) {
Student student = new Student();
student.setName("Daniel");
System.out.println(student.getName());
student.setAge(999);//不符合实际,因此Student做了判断
System.out.println(student.getAge());
}
}
运行结果为:
4.2 继承
(1)创建父类
public class Person {
private double money = 1_0000_0000;
public void like(){
System.out.println("喜欢养花");
}
public double getMoney() {
return money;
}
public void setMoney(double money) {
this.money = money;
}
}
(2)创建子类继承父类
public class Student extends Person {
public static void main(String[] args) {
Person person = new Person();
person.like();
System.out.println(person.getMoney());
}
}
运行结果为:
查看上下级继承:ctrl+h----------------------->所有的类都继承Object类
4.1.1 this & super
(1) 创建父类 Person
public class Person {
protected String name = "Kendra";
//private int age = 11;
}
(2)创建子类Student并且继承父类
public class Student extends Person{
private String name = "Daniel";
public void su(){
System.out.println(this.name); //子类
System.out.println(super.name); //父类
//System.out.println(this.age);
}
}
(3)创建应用抽象类Application
public class Application {
public static void main(String[] args) {
Student student = new Student();
student.su();
}
}
运行结果为:
super注意点:
- super调用父类的构造方法,必须在构造方法的第一个
- super必须只能出现在子类的方法或者构造方法中!
- super和this不能同时调用构造方法!
this || super
(1)代表的对象不同:
- this:本身调用者这个对象
- super: 代表父类对象的应用
(2)前提
- this:没有继承也可以使用
- super:只能在继承条件才可以使用
(3)构造方法
- this();本类的构造
- super():父类的构造!
4.1.2 重写
- 在子父类中,出现了不同名的方法
- 子类可以直接调用父类的方法,也可以调用子类的特有方法
- 在子父类中,出现了同名的方法
- 在子父类中,出现了一模一样的方法声明,而两个方法的实现内容却不一样
- 作用:在子类中,如果你不想修改父类中的方法声明,但是还想修改方法的实现内容,这时候就需要使用重写。
- 方法的重写和方法的重载:
- 重载:在同一个类中,方法名相同,参数列表不同,与返回值类型无关
- 重写:在子父类中,方法名相同,参数列表相同,与返回值类型有关(相同)
别名:Override,覆写、覆盖
- 方法重写的检查:
- @Override
- 让编译器帮助我们检查,当前的这个方法,究竟是否是对父类方法的重写。
- 说明:
- 方法本身还是属于父类,只是在子类中重新实现了这个方法的内容。
(1)子父类的创建
public class Fu {
public void chong(){
System.out.println("父类的方法");
}
}
class Zi extends Fu{
@Override
public void chong() {
System.out.println("子类的方法");
super.chong();
}
}
(2)抽象创建类
public class Application {
public static void main(String[] args) {
Fu fu = new Fu();
fu.chong();
Fu f = new Zi();
f.chong();
}
}
运行结果显示为:
重写:需要有继承关系,子类重写父类的方法!
- 方法名必须相同
- 参数列表必须相同
- 修饰符:范围可以扩大但不能缩小: public>Protected>Default>private
- 抛出的异常:范围,可以缩小,但不能扩大;ClassNotFundException–>Exception(大)
- 重写,子类的方法的父类的必要一致;方法体不同!
- 为什么需要重写:
- 父类的功能,子类不一定需要,或者不一定满足!
Alt+Insert; Override;
4.3 多态
4.3.1 多态中成员变量的访问特点
1、编译看左边,运行看左边
2、编译的时候,要看【=】左边的引用的类型中,是否有该变量的定义,如果有,就编译成功,如果没有,就编译失败。
3、运行的时候,要看【=】左边的引用所属类型中,真正如何给变量赋值的。获取到的是引用父类的赋值结果。
public class BianLiangTeDian {
public static void main(String[] args) {
/*
在多态中成员变量的访问特点
*/
Animal zoo = new Cat();
//2、编译的时候,要看【=】左边的引用的类型中,是否有该变量的定义,如果有,就编译成功,如果没有,就编译失败。
//System.out.println(zoo.color);
//3、运行的时候,要看【=】左边的引用所属类型中,真正如何给变量赋值的。获取到的是引用父类的赋值结果。
System.out.println(zoo.age);
}
}
class Animal {
int age = 10 ;
}
class Cat extends Animal {
int age = 20;
String color;
}
运行结果为:
public class Daniel_DuoTai {
public static void main(String[] args) {
Animals animals = new Cats();
System.out.println(animals.name);
//System.out.println(animals.age);//编译看左边,运行看左边
/*
在多态中成员变量的访问特点
2、编译的时候,要看【=】左边的引用的类型中,是否有该变量的定义,如果有,就编译成功,如果没有,就编译失败。
3、运行的时候,要看【=】左边的引用所属类型中,真正如何给变量赋值的。获取到的是引用父类的赋值结果。
*/
}
}
class Animals{
String name;
}
class Cats extends Animals{
String name = "Daniel";
int age = 10;
}
运行结果为:
4.3.2 多态中成员方法的访问特点
1、编译看左边,运行看右边
2、编译的时候,要看【=】左边的引用所属的类型中,是否有该方法的定义,如果有,就编译成功,如果没有,就编译失败。
3、运行的时候,要看【=】右边的对象所属的类型中,是如何实现这个方法的。最终运行的是子类重写过的方法实现。
public class Daniel_DuoTai {
public static void main(String[] args) {
Animals an = new Cats();//父类的引用指向子类的对象
System.out.println(an.name);
//成员变量访问特点,编译看=左边,运行也看=左边
System.out.println(an.age);
an.eat();//成员方法的访问特点,编译看= 左边,运行看=右边
//an.run();//没有重写,只能强制转换才可访问如下:
((Cats) an).run();
}
}
class Animals{
String name;
int age = 99;
public void eat(){
System.out.println("真能吃");
}
//
}
class Cats extends Animals{
String name = "Daniel";
int age = 10;
@Override
public void eat() {
System.out.println("吃酒喝水");
}
public void run(){
System.out.println("全民健身");
}
}
运行结果为:
4.3.3 多态中静态方法的访问特点
1、编译看左边,运行看左边
2、编译的时候,要看【=】左边的引用所属的类型中,是否有该方法的定义,如果有,就编译成功,如果没有,就编译失败
3、运行的时候,要看【=】左边的引用所属的类型中,如何实现该方法的。最终运行的是引用所属类型中该方法的实现。(方法属于类,和父类的方法不属于重写关系)
4、静态最终解释:
静态变量:存储在类的字节码中的变量,被所有对象所共享,不随着对象的变化而变化,都有相同的值,所以称为静态变量
静态方法:只会根据引用所属的父类,来决定运行的内容,运行内容,不会随着子类的变化而变化,都是引用所属的父类的方法实现,所以称为静态方法。
public class Daniel_DuoTai {
public static void main(String[] args) {
Animals an = new Cats();//父类的引用指向子类的对象
//编译看左边,运行看左边
an.speak();
}
}
class Animals{
public static void speak(){
System.out.println("懂礼貌,树新风");
}
}
class Cats extends Animals{
//@Override 静态方法不能被重写
public static void speak(){
System.out.println("人之初,性本善");
}
}
运行结果为:
多态的注意事项
- 多态是方法的多态,属性没有多态
- 父类和子类,有联系,类型转换异常!ClassCastException!
- 存在条件:继承关系,方法需要重写,父类引用指向子类对象!Father f1 = new Son();
哪些方法不能重写:
- static方法,属于类,它不属于实例
- final常量;
- private方法;
4.3.4 instanceof(向上向下转型)
(类型转换)引用类型,判断一个对象是什么类型~
- 向上转型:
使用子类的引用指向子类的对象(正常情况)
多态中,使用父类的引用指向子类的对象(向上转型)
本质:缩小了对象本身的访问范围,减少了访问的权限(只能访问父类中定义的内容)- 向下转型:
概念:
让指向子类对象的父类引用,【恢复】成子类的引用
格式:
子类类型 引用名称 = (子类类型)父类类型的引用
SuperMan sm = (SuperMan)m;
本质:
【恢复】子类类型原本就有的访问范围
public class XiangShangXiangXia {
public static void main(String[] args) {
//超人案例
Man m = new SuperMan();//向上转型.自身的访问权限变小了
System.out.println(m.name);//普通人的名字
m.business();
//m.fly();普通人不能飞,不能调用fly()方法
//向下转型
SuperMan sm = (SuperMan)m;
//double b = 20.3333;
//int a = (int)b;
// System.out.println(a);
sm.fly();
}
}
class Man {
String name = "KangKang";
public void business(){
System.out.println("卖煎饼果子");
}
}
class SuperMan extends Man{
String name = "SpiderMan";
public void business(){
System.out.println("敲代码");
}
public void fly(){
System.out.println("我要去拯救世界了");
}
}
运行结果为:
4.3.5 static
public class Staticc {
//2.赋初值
{
System.out.println("匿名代码块");
}
//1 只执行一次
static {
System.out.println("静态代码块");
}
//3
public Staticc() {
System.out.println("构造代码块");
}
public static void main(String[] args) {
Staticc staticc = new Staticc();
}
}
运行结果为:
package duotai;
import static java.lang.Math.random;//静态导入包
public class Demo_Daniel {
public static void main(String[] args) {
System.out.println(random());
System.out.println(Math.random());//无需静态导入包
}
}
五、抽象类和接口
5.1 抽象类
5.1.1 抽象方法
抽象
:抽取像的、相同的、相似的内容出来抽象方法
:只有方法声明,而没有方法实现的方法,就是抽象方法
在各个子类中,对于某个方法都有自己不同的实现,所以实现各不相同,无法抽取,只能抽取方法的声明上来,在父类中,方法就只有方法声明没有方法体。就是抽象方法。- 定义格式:
(1)没有方法实现,连大括号都没有,直接在方法声明后面加上一个分号,表示方法定义结束 public abstract void test();
(2)为了将方法标记为抽象方法,需要在方法前面加上一个abstract关键字
//abstract 抽象
public abstract class Abstract_Daniel {
/**
* 约束~有人帮我们实现
* abstract ,抽象方法,只有方法名字,没有方法的实现
*/
public abstract void main();
/**
* 1.不能new这个抽象类,只能靠子类去实现它;约束!
* 2.抽象类中可以写普通的方法
* 3.抽象方法,必须在抽象类中
* 抽象的抽象:约束~
*/
}
5.1.2 抽象类的特点
- 抽象类和抽象方法都需要使用
abstract
关键字修饰
- 抽象类:
abstract class {}
- 抽象方法:
public abstract void test();
Public private protected
这些称之为修饰符
- 抽象类和抽象方法的关系:
- 抽象方法所在的类必须是抽象类
- 抽象类中未必一定都定义抽象方法,抽象类中未必存在抽象方法
- 抽象类的实例化(抽象类如何创建对象)
- 抽象类不能直接实例化(不能创建对象)
- 定义抽象类的子类,由子类创建对象,调用方法
- 抽象类子类
- 在子类中,将父类所有的抽象方法全部重写(实现),子类就成了一个普通类,就可以创建对象
- 在子类中,没有将父类中所有的抽象方法全部实现,子类就还是一个抽象类,还需要使用abstract关键字修饰子类。
class Daniel_AbstractClass {
public static void main(String[] args) {
//Animal an = new Animal();//抽象类不能直接实例化
Cat c = new Cat();
}
}
abstract class Animal {
//抽象方法
public abstract void speak();
public abstract void eat();
/* public void sleep(){//抽象类中不一定全部是抽象方法
System.out.println();
}*/
}
class Cat extends Animal {
@Override
public void speak(){
System.out.println("喵喵喵");
}
@Override
public void eat(){
System.out.println("猫吃鱼");
}
}
abstract class Pig extends Animal {
@Override
public void speak(){
System.out.println("哼哼哼");
}
public abstract void eat();
}
5.1.3 抽象类成员特点
- 成员变量:可以定义变量,也可以定义常量,但是不能被抽象
- 构造方法:有
- 虽然本类无法创建对象,但是抽象类一定有子类,子类会访问父类的抽象方法。
- 是否有构造方法,不取决于是否可以创建对象,而是取决于是否可以定义成员变量。如果可以定义成员变量,那么就需要初始化成员变量,就是构造方法来完成的。
- 成员方法:
- 既可以是抽象方法:强制子类重写
- 也可以是非抽象方法:用于给子类继承,提高代码的复用性
5.2 接口
5.2.1 接口的概述
- 广义:一切定义规则的都是接口
- 狭义:java中用于定义方法命名的规则就是接口
- Java接口中,全都是方法的声明,都是抽象方法
- 好处:
- 一旦将命名规则定义出来,【方法的调用】和【方法的实现】就分离开了,可以提升开发效率,降低代码的耦合性
(1)创建接口UserService
public interface UserService {
void add(String name);
void delete(String name);
void update(String name);
void query(String name);
}
(2)创建接口实现类UserServiceImpl
//interface 关键字
//接口可以多继承
//接口一旦定义就要实现接口
public class UserServiceImpl implements UserService,TimeService {
@Override
public void add(String name) {
}
@Override
public void delete(String name) {
}
@Override
public void update(String name) {
}
@Override
public void query(String name) {
}
@Override
public void time() {
}
}
(3)再次创建接口TimeService
public interface TimeService {
void time();
}
5.2.2 接口的特点
- 接口的定义:使用
interface
关键字,编译也是生成一个【.class】(字节码文件)文件
interface 接口名称 {
方法声明的定义;
}
- 接口中,只可以声明抽象方法(只能定义方法起名字的规则)
- 类可以实现接口:使用implements关键字
- 实现:接口中只有方法名称的定义,在类中把接口方法的真正完成逻辑写出来
class 类名称 implements 接口名称 {
对接口中方法的实现;
}
- 接口的实例化:不能直接实例化
- 定义实现类,实现接口,类创建对象,对象调用方法
- 接口的实现类:
- 如果是一个抽象类,该类没有实现接口中的所有抽象方法
- 如果是一个普通类,该类实现了接口中的所有抽象方法
public class Computers {
public static void main(String[] args) {
//创建一个电脑对象
Computer cm = new Computer();
cm.start();
//连键盘
cm.useUSB(new Keyboard());
//连鼠标
cm.useUSB(new Mouse());
cm.playGame();
cm.shutdown();
}
}
class Computer{
//开机的方法
public void start(){
System.out.println("开机");
}
//关机的方法
public void shutdown(){
System.out.println("关机");
}
public void playGame(){
System.out.println("开始打游戏");
}
//使用USB接口
public void useUSB(USB u){//多态的一种体现
u.use();
}
}
interface USB {
public abstract void use();
}
class Keyboard implements USB{
//将键盘连到我们的USB接口上
@Override
public void use(){
System.out.println("键盘已连接");
}
}
class Mouse implements USB {
//将鼠标连到我们的USB接口上
@Override
public void use() {
System.out.println("鼠标已连接");
}
}
运行结果为:
接口的作用:
- 约束
- 定义一些方法,让不同的人实现
- public abstract
- public static final
- 接口不能被实例化,接口中没有构造方法
- implements可以实现多个接口
- 必须要重写接口中的方法
六、内部类
6.1 内部类
6.1.1 成员内部类
(1)创建外部和内部类(外部类Outer,内部类Inner)
/**
* 一个类中只有一个public class 类,但可以有多个class 类
*/
public class Outer {
private int id = 10;
public void outer(){
System.out.println("外部成员类的方法");
}
public class Inner{
public void in(){
System.out.println("内部成员类的方法");
}
public void getId(){
System.out.println(id);
}
}
}
(2)创建测试类
public class Application {
public static void main(String[] args) {
Outer outer = new Outer();
Outer.Inner inner = outer.new Inner();
inner.in();
inner.getId();
}
}
运行结果为:
6.1.2 静态内部类
静态内部类只需在上面public 后面加上static就可以,静态无法访问非静态。
6.1.3 局部内部类
public class JuBuNeiBuLei {
public void ju(){
System.out.println("成员");
class A{
//局部
}
}
}
6.1.4 匿名内部类
public class NiMing {
public static void main(String[] args) {
//没有名字初始化类,不用讲实例保存到变量中~
new Apple().eat();//匿名
new UserService(){
@Override
public void add() {
}
};
}
}
class Apple{
public void eat(){
System.out.println("吃苹果");
}
}
interface UserService{
public void add();
}
运行结果为:
七、异常(了解)
7.1 异常概述
- 在java程序运行过程中,出现的不正常情况,出现的错误,称为异常
- 异常就是一个对象,描述那些不符合生活正常情况的异常情况,包含了这些情况的原因、类型、描述以及位置,这些内容都封装到异常对象中。
- 异常也是一种处理异常情况的机制,可以进行跳转、捕获以及结束程序
public class Exception_Daniel {
public static void main(String[] args) {
System.out.println(11/0);
}
}
运行结果:
7.2 异常体系
- Throwable:可抛出的,是异常体系的顶层父类,其他的异常或者错误都是Throwable的子类类型,只有Throwable的体系类型,才可以使用异常的处理机制
- Error:错误,是Throwable的子类,用于描述那些无法捕获和处理的错误情况,属于非常严重的错误,StackOverflowError
- Exception:异常,是Throwable的子类,用于描述那些可以捕获和处理的例外情况,属于不太严重的错误,ArrayIndexOutOfBoundsException
- RuntimeException:运行时异常,是Exception的特殊的子类,在编译阶段不做检查的一个异常
- 体系图:
- Throwable
– Error
— Exception
— RuntimeException
在jvm中默认处理异常的机制
- 在代码的某个位置,出现了和正常情况不同的情况,就将异常情况封装到一个异常对象中。
- 将异常对象抛给调用该方法的方法
- 某个方法接收到底层方法抛上来的异常,也没有办法自己处理,继续向上抛出,最终抛给主方法,主方法也没有办法处理,抛给调用自己的jvm虚拟机
- Jvm虚拟机是我们手动调用的,只能将异常对象的所有信息,通过错误流打印出来,结束jvm虚拟机
- 总结,jvm默认处理的方式:【一层一层向上抛,jvm接收到之后结束自己】
ERROR
Exception
7.3 异常处理机制
异常解决:
public class TryCatch {
public static void main(String[] args) {
int a = 2;
int b = 0;
try {
System.out.println(a/b);
}catch (Exception e){
System.out.println("程序出现异常了");
//e.printStackTrace();
}finally {
System.out.println("不管咋样我都要执行");
}
}
}
运行结果为:
7.4 throw和throws的比较
- throw是对异常对象的
抛出
,throws是对异常类型的声明
- throw是对异常对象实实在在的抛出,一旦使用了throw关键字,就一定有一个异常对象出现;throws是对可能出现的异常类型的声明,即使声明了一些异常类型,在这个方法中,也可以不出现任何异常。
- throw后面只能跟一个异常对象;throws可以跟很多个异常类型
7.5 自定义异常
实际应用中的经验总结
计算年龄案例
package com.zql3;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Scanner;
/**
* @author Daniel
* 已知生日算年龄
*/
public class Demo5 {
public static void main(String[] args) throws ParseException {
Scanner scanner = new Scanner ( System.in );
System.out.println ("please input your birthday:ex:2022-05-01");
String birthday = scanner.nextLine ();
SimpleDateFormat simpleDateFormat = new SimpleDateFormat ( "yyyy-MM-dd" );
long time = simpleDateFormat.parse ( birthday ).getTime ();
long now = System.currentTimeMillis ();
System.out.println ((now-time)/1000/3600/24/365);
}
}
最终运行效果: