JavaSE——02核心面向对象及常用类

目录

02 核心面向对象及常用类

01、面向对象与面向过程

1.1 面向对象

1.2 面向过程和面向对象的区别

02、类的定义

2.1 语法结构

2.2 基本数据类型

2.3 引用数据类型

03、成员/实例/对象变量、实例(对象)

3.1 对象的基本性质

3.2 成员变量、实例变量、静态变量(类变量)、局部变量

04、对象的创建和使用

4.1 对象和引用的定义

4.2 对象的创建

4.3 JVM三大内存

4.4 对象的访问

4.5 实例

4.6 夫妻类

4.7 JVM

4.8 空指针异常

4.9 关联关系和继承关系

05、封装

5.1 封装的好处

5.2 如何封装

5.3 封装后如何访问

06、继承

07、多态

7.1 关于java语言中多态语言机制:

7.2 instanceof

7.3 多态语法的作用

08、构造方法

8.1 定义

8.2 构造方法的语法结构

8.3 构造方法的调用

8.4 方法有无static方法的调用

8.5 构造方法的作用

8.6 自动构造方法的快捷方式

8.7 面向对象的封装以及构造方法的实例

09、this

9.1 this关键字的定义和性质

9.2 实例方法与实例变量

9.3 静态方法

9.4 特例:实例方法中实例方法的访问

9.5 实例方法和实例变量的定义和访问的比较

9.6 this的作用领域

9.7 两种方法调用以及实例变量的访问的完整/省略写法

10、static

10.1 static关键字的定义和性质

10.2 实例变量与静态变量

10.3 静态代码块

10.4 *实例语句块 / 代码块

10.5 static总结

11、final

12、package

13、import

14、super

14.1 super和this的共同特征

14.2 super和this不同的特征

14.3 何时使用,何时省略super关键字?

15、方法覆盖

16、常量

17、访问控制权限修饰符

18、抽象类

18.1 什么是抽象类?

18.2 抽象类属于什么类型?

18.3 抽象类怎么定义?

18.4 抽象方法

19、接口

19.1 关于接口

19.2 接口怎么定义?

19.3 接口基础语法

19.4 接口在开发的作用

19.5 抽象类和接口的语法区别

20、关于Object类

20.1 什么是ApI?

20.2 Object类中的方法

20.3 关于toString方法

20.4 关于equals方法

20.5 关于finalize()方法

20.6 关于hashCode方法

21、内部类

21.1 定义

22.2 内部类的分类

22.3 代码解释

22.4 匿名内部类

22、java程序基础练习题

22.1 题目一:Vehicle driving

22.2 题目二:calculator

22.3 题目三:People Message

22.4 题目四:Add Time

23、包装类

23.1 引入包装类的目的

23.2 关于包装类

23.3 关于部分包装类的父类Number

23.4 Integer类的构造方法

23.5 自动装箱/拆箱

23.6 数字格式化异常

23.7 Integer中常用方法

23.8 String、int、Integer三者的互相转换

24、对时间的处理

24.1 获取系统当前时间(精确到毫秒的系统当前时间)

24.2 日期格式化

25、System类

26、*数字格式化

27、高精度BigDecimal

28、随机数

28.1 new Random()

28.2 Math.random()可以设置上下限

28.3 *currentTimeMillis()

29、枚举类型的使用

30、异常

30.1 基本概念

30.2 编译时异常和运行时异常

30.3 对异常的处理

30.4 深入try…catch异常

30.5 上报和捕捉如何选择

30.6 getMessage()方法和printStackTrace()方法

30.7 finally子句

30.8 final、finally和finalize的区别

30.9 自定义异常

30.10 子类重写的方法抛出编译异常只能更少/小不能更多


02 核心面向对象及常用类

01、面向对象与面向过程

1.1 面向对象

1.1.1 三大特性

三大特性:封装、继承、多态;

面向对象的分析 OOA

面向对象的设计 OOD

面向对象的编程 OOP

1.1.2 类与对象

对象抽象化找出共同特征定义为类(类是属性、模板、概念);

对象(个体)真实存在;

不存在,是虚拟的;

类---->对象(通过实例化);

对象---->类(通过抽象化);

状态---->一个类的属性(通过对象的状态信息);

动作---->一个类的方法(描述对象的动作信息);

注意:

状态和动作当具体到某个对象上之后,发现最终的结果可能不一样;

对象和对象之间有共同的特征,但是具体到对象之后有数据的差异。


1.2 面向过程和面向对象的区别

1.2.1 面向过程:

主要关注点是:实现的具体过程,因果关系【集成显卡的开发思路】

*优点:

对于业务逻辑比较简单的程序,可以达到快速开发,前期投入成本较低;

*缺点:

采用面向过程的开发很难解决非常复杂的业务逻辑,另外面向过程的方式导致软件元素之间的”耦合度“非常高,只要其中一环出问题,整个系统受到影响,导致最终的软件”扩展力“差。另外由于没有独立体的概念,所以无法达到组件复用。

1.2.2 面向对象:

主要关注点是:主要关注对象}【独立体】能完成哪些功能。【独立显卡的开发思路】

*优点:

耦合度低,扩展力强。更容易解决现实世界当中更复杂的业务逻辑。组合复用性强。

*缺点:

前期投入成本高,需要进行独立体的抽取,大量的系统分析和设计。

-C语言是纯面向过程的、C++半面向对象、Java纯面向对象


02、类的定义

2.1 语法结构

[修饰符列表] class 类名{

}

String不属于基本数据类型,是一个字符串类型,也是一个引用类型;

引用数据类型还包括:类,接口,数组;

String是SUN在JavaSE中提供的字符串类型;

String.class字节码文件;

重点:

1、属性通常是采用一个变量的形式来完成定义的;

2、在类体当中,方法体之外定义的变量被称为"成员变量",成员变量没有赋值,系统赋默认值:一切向0看齐;

2.2 基本数据类型

byte、short、int、long、float、double、boolean、char;

2.3 引用数据类型

String.class SUN提供的;

System.class SUN提供的;

Student.class 程序员自定义的(是一个类,类型,引用数据类型);

03、成员/实例/对象变量、实例(对象)

3.1 对象的基本性质

1)类体=属性+方法,属性【存储数据采用变量的形式】;

2)对象又被称为实例,实例变量又被称为对象变量【对象级别的变量】;

3)不创造对象,这个变量的内存空间是不存在的,只有创建了对象,这个变量的内存空间才会被创建;

3.2 成员变量、实例变量、静态变量(类变量)、局部变量

1)成员变量:作用范围是整个类,相当于C中的全局变量,定义在方法体和语句块之外,一般定义在类体当中;成员变量包括实例变量和静态变量(类变量);

成员变量没有手工赋值的话,系统默认值如下:

数据类型								默认值

————————————————————————————————————————————————

byte,short,int,long 					0;

float,double						   0.0;

boolean								  false;

char								  \U000;

引用数据类型						       null;

2)实例变量:独立于与方法之外的变量,无static修饰,声明在一个类中,但在方法、构造方法和语句块之外,数值型变量默认值为0,布尔型默认值为false,引用类型默认值为null;

*实例变量不能通过“类名”去访问,必须通过引用;

*实例变量在堆内存的java对象内存中存储;

3)静态变量(类变量):独立于方法之外的变量,用static修饰,默认值与实例变量相似,一个类中只有一份,属于对象共有,存储在(方法区内存)静态存储区,经常被声明为常量,调用一般是类名.静态变量名,也可以用对象名.静态变量名调用;

public static String level = "SSS"; *//成员变量、静态变量(类变量)*

4)局部变量:类的方法中的变量,访问修饰符不能用于局部变量,声明在方法、构造方法或语句块中,在栈上分配,无默认值,必须经初始化;


04、对象的创建和使用

4.1 对象和引用的定义

new运算符在栈内存中开辟的内存空间称为对象;

引用是一个变量,只不过这个变量中保存了另一个java对象的内存地址;

1)与C语言中的指针不同,指针可以指向内存空间的任意一块地址

2)java中无指针,不能直接操作堆内存,只能通过“引用”访问堆内存中对象的实例变量(保证了java语言的安全性

4.2 对象的创建

1)通过一个类可以实例化多个对象,实例化的语法:new 类名();

2)new是java语言中的一个运算符,其作用是创建对象,在JVM堆内存中开辟新的内存空间;

3)将对象产生关系,协助起来,形成一个系统;

int i = 10;

int 是一个基本数据类型;i是一个变量名;10是int类型的字面值;

Student s = new Student( );

Student 是一个引用数据类型s局部变量在栈内存中存储】表示引用;**new Student()**是创建一个学生对象;

4.3 JVM三大内存

方法区内存:在类的加载的时候,class字节码代码片段会被加载到该内存空间;

栈内存(局部变量):方法代码片段在执行的时候会给该方法分配内存空间,在栈内存中压栈;

堆内存:new的对象在堆内存中存储;

4.4 对象的访问

访问实例变量的语法格式:

读取数据:引用.变量名;

修改数据:引用.变量名 = 值;

4.5 实例

//用户类
public class User{
	int no;//基本数据类型	实例变量 
	String name;//引用数据类型 实例变量
	Address addr;//引用数据类型  实例变量
}
//家庭住址类
public class Address{
	String city;//引用数据类型  实例变量  city是一个引用:保存内存地址的一个变量,该变量保存内存地址指向了堆内存;
	String street;
	String zipcode;
}
//测试类1
public class helloworld{
    public static void main(String[] args){
		User u = new User();
         System.out.println(u.no);
         System.out.println(u.name);
         System.out.println(u.addr);
         u.no = 110;
         u.name = "jack";
		u.addr = new Address();
    }
}
//测试类2
public class helloworld{
    public static void main(String[] args){
		User u = new User();
    	Address a = new Address();
        u.addr = a;
        System.out.println(u.addr.city);
        a.city = "天津";
        System.out.println(u.addr.city);
    }
}

4.6 夫妻类

//丈夫类
public class Wife{
	String name;
	Husband h;//丈夫对象当中含妻子引用
}
//妻子类
public class Husband{
	String name;
	Wife w;//妻子对象当中还有丈夫引用
}
public class Code{
	public static void main(String[] args){
        //创建一个丈夫对象
		Husband huang = new Husband();
		huang.name = "黄晓明";
        //创建一个妻子对象
		Wife baby = new Wife();
		baby.name = "baby";
        //结婚【通过丈夫找到妻子,也可以通过妻子找到丈夫】
        huang.w = baby;
        baby.h = huang;
        //得到黄晓明的妻子的名字
        System.out.println(huang.name + "妻子的名字是" + huang.w);
	}
}

4.7 JVM

4.7.1 内存区

当中变化最频繁的是栈内存,最先有数据的是方法去内存,垃圾回收器主要针对的是堆内存;

4.7.2 垃圾回收器【自动垃圾回收机制、GC机制】

什么时候考虑将某个java对象的内存回收呢?

1)当栈内存当中java对象称为垃圾数据的时候,会被垃圾回收器回收;

2)什么时候堆内存的java的对象会变成垃圾呢?
-没有更多的引用指向它的时候;

-这个对象无法被访问,因为访问对象只能通过引用的方式访问;

4.8 空指针异常

public class Code{
	public static void main(String[] args){
        Customer c = new Customer();
        System.out.println(c.id);
        c=null;
        //以下程序编译可以通过,因为符合语法,	   	//运行出现空指针异常
        //空引用访问“实例”相关的数据一定会出现空指针异常
        //java.lang.NullPointerException
        System.out.println(c.id);
	}
}

在这里插入图片描述

4.9 关联关系和继承关系

关联关系:A has a B【A对象中含有B对象的引用】;

继承关系:A is a B【关系更加紧密】;

Surpass Day06——Java 面向对象的封装、构造方法

05、封装

5.1 封装的好处

1)封装之后对于那个事物来说,看不到这个事物比较复杂的那一面,只能看到该事物简单的那一面,复杂性封装,对外提供简单的操作入口;

2)封装之后才会形成真正的"对象",真正的"独立体";

3)封装之后意味着以后的程序可以重复使用,并且这个事物适应性比较强,在任何场所都能够使用;

4)封装之后,对于事物本身提高了安全性;

5.2 如何封装

5.2.1 属性私有化

使用private关键字进行修饰,修饰的所有数据只能在本类中访问;

5.2.2 对外提供简单的操作入口(两个公开的方法)

-调用set方法:修改属性;

-调用get方法:读取属性;

5.2.3 set方法的命名规范

public void setAge(int a){
    //编写业务逻辑代码进行安全控制 if()
	age = a;
}

由于java有就近原则,以下代码Error

public void setAge(int age){
	this.age = age;
}//这里并没有给age属性赋值,这里的age都是局部变量age

5.2.4 get方法的命名规范

public int getAge(){
    //编写业务逻辑代码进行安全控制 if()
	return age;
}

而在eclipse中get和set方法不用写,直接按下面操作自动生成get,set方法

单击右键—>Source—>Generate Getters and Setters

在这里插入图片描述
在这里插入图片描述

5.3 封装后如何访问

调用方法:

修改:user.setAge(-100);

读取:user.getAge();

注意:不能通过"类型.变量名"访问,已经封装在类中,外部无法访问,只能通过方法;


06、继承

1)继承是面向对象的三大特征之一,三大特征分别是:封装、继承、多态;

2)继承"基本"的作用是,代码复用。最重要的作用是:有了继承之后才有的"方法的覆盖"和"多态机制";

3)继承语法格式:

[修饰符列表] class 类名 extends 父类名字{
	类名 = 属性 + 方法;
}

4)java语言当中的继承只有单继承,一个类不能同时继承很多类,只能继承一个类。在C++中支持多继承;

5)关于继承中的一些术语:

B类继承A类,其中:

​ A类称为:父类、基类、超类、superclass;

​ B类称为:子类、派生类、subclass

6)java语言中能继承父类的哪些数据?

  • 私有的不支持继承;
  • 构造方法不支持继承;
  • 其他数据都有被继承;

7)虽然java语言当中只支持单继承,但是一个类也可以间接继承其他类,例如:

C extends B{
}
B extends A{
}
A extends T{
}
//C直接继承B类,但是C类间接继承T、A类;

8)java语言中假设一个类没有显示继承任何类,该类默认继承JavaSE库中提供的java.lang.ob.jact类;

public class helloworld{
    public static void main(String[] args){
		C c = new C();
 		c.doSome();//这里调用的doSome方法是从B类在继承过来的doSome方法
    }
}
class A{
    public void doSome(){
        System.out.println("do some!");
    }
}
class B extends A{
}
class C extends B{
}

9)eclipse快速继承
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述


07、多态

7.1 关于java语言中多态语言机制:

1)Animal、Cat、Bird三个类之间的关系:

​ Cat继承Animal;
​ Bird继承Animal;
​ Cat和Bird之间没有任何继承关系;

2)向上转型(upcasting)
子类型——>父类型(自动转换)

  • 编译通过,运行一定可以

​ 向下转型(downcasting)
​ 父类型——>子类型(强制类型转换)【需要加强制类型转换符】

  • 编译通过,运行不一定通过,存在隐患

3)无论是向上转型还是向下转型,两者必须要有继承关系;

public class helloworld {
	public static void main(String[] args) {
		Animal a = new Animal();
		a.move();
		
		Bird b = new Bird();
		b.move();
		
		Animal a2 = new Bird();//1.1.1关于该语句的解读
		a2.move();
		
		ERROR:a2.eat();	//1.1.2关于该语句的解读
		Bird c2 = (Bird)a2;
		c2.eat();
        
		Animal a3 = new Cat();
		Bird c3 = (Bird)a3;//1.1.3关于该语句的解读
        
		
	}
}

class Animal {
	public void move() {
		System.out.println("动物会跑");
	}
}

class Bird extends Animal {
	//重写父类中继承的方法
	public void move() {
		System.out.println("鸟会跑");
	}
	//这个方法不是从父类中继承过来的,是子类中特有的行为
	public void eat() {
		System.out.println("鸟吃虫");
	}
}

1.1.1 关于Animal a2 = new Bird();

1)java程序分为编译阶段和运行阶段,编译不通过,是根本无法运行的

2)编译阶段,编译器检查a2这个引用的数据类型为Animal,由于Animal.class字节码文件当中有move()方法,所以编译通过了。这个过程我们称为静态绑定,编译阶段绑定,只有静态绑定成功之后才有后续的运行;

3)程序运行阶段,JVM堆内存当中真实创建的对象是Bird对象,那么以下程序在运行阶段一定会调用Bird对象的move方法,此时发生程序的动态绑定,运行阶段绑定;

4)无论是Bird类有没有重写move方法,运行阶段一定调用的是Bird对象的move方法,因为底层真实的对象就是Bird对象

5)父类型引用指向子类型对象这种机制导致程序存在编译阶段绑定运行阶段绑定的两种不同形态这种机制可以成为一种多态语法机制;

1.1.2 关于a2.eat();

1)不能调用的原因:
因为编译阶段编译器检查到a2的类型是Animal类型,从Animal.class字节码文件当中查找eat()方法,最终没有找到该方法,导致静态绑定失败,没有绑定成功,也就是编译失败,别谈运行了;

2)如何调用a2.eat?

a2是无法直接调用的,因为a2的类型的Animal,Animal中没有eat()方法,想要调用,必须将a2强制转换成Bird类型,a2的类型是animal(父类),转换成BIrd类型(子类),需要向下转型,被称为向下转型(强制类型转换),需要加强制类型转换符;

向下转型的使用时刻:

当父类中没有子类的特有的方法,必须使用向下转型

1.1.3 关于Bird c3 = (Bird)a3;

1)编译是没有问题的,因为编译器检查到a3的数据类型是Animal,Animal和Bird之间存在继承关系,并且Animal是父类型,Bird是子类型,父类型转换成子类型叫做向下转型,语法合格;

2)程序虽然通过了,但是程序在运行阶段会出现异常,因为JVM堆内存当中真实存在的对象是Cat类型,Cat类型无法转换成Bird对象,两种对象之间不存在继承关系,此时出现了著名的异常java.lang.classCatexception,类型转换异常,这种异常总是在"向下转型"的时候发生;

7.2 instanceof

使用instanceof可以避免向下转型出现的java.lang.classCatexception

1)语法格式:

(引用 instanceof 数据类型名)

2)运算符的执行结果是布尔类型,结果可能是true/false

3)关于运算结果(true/false)

假设:(a instanceof Animal)//a的实例化是动物吗?

true表示
a这个引用指向的对象是Animal类型

false表示
a这个引用指向的对象不是Animal类型

if(a3 instanceof Cat){
	Cat c3 = (Cat)a3;
	c3.catchMouse();
}eles if(a3 instanceof Bird){
	Bird b2 = (Bird)a3;
}

7.3 多态语法的作用

1)降低程序的耦合度,提高程序的扩展力

2)能使用多态尽量使用多态

3)父类型引用指向子类型对象

public class helloworld {
	public static void main(String[] args) {
		Master zhangsan = new Master();
//		Cat tom = new Cat();
//		Dog amy = new Dog();
//		zhangsan.feed(tom);
//		zhangsan.feed(amy);
		zhangsan.feed(new Cat());//上面四行代码和这两行实现的功能相同
		zhangsan.feed(new Dog());
        //new 具体宠物对象的形参传到Pet pet中
        //相当于Pet pet = new Dog(); 
	}
}
class Master {
	public void feed(Pet pet) {//Pet pet是一个父类型的引用
		pet.eat();
	}
}
class Cat extends Pet{
	public void eat() {
		System.out.println("猫吃鱼!");
	}
}
class Dog extends Pet{
	public void eat() {
		System.out.println("狗吃肉!");
	}
}
class Pet {
	public void eat() {
	}
}

08、构造方法

8.1 定义

构造方法又被称为构造函数/构造器/Constructor

8.2 构造方法的语法结构

[修饰符列表]  构造方法名 (形式参数列表){

	构造方法体;	

}

与普通方法的语法结构对比:

[修饰符列表] 返回值类型 方法名(形式参数列表){

		方法体;

}

注意:

1)"返回值类型"不需要指定,也不用写void;

写上void就变成了普通方法了;

2)构造方法名必须与类名相同;

8.3 构造方法的调用

1)普通方法的调用:

方法修饰符有static时:类名.方法名(实参列表)

方法修饰符没有static时:引用.方法名(实参列表);(需要先创建对象)

2)构造方法的调用:
new 构造方法名(实参列表)

3)构造方法执行之后有返回值,且返回值类型为构造方法所在类的类型(他本身),所以语法结构中不用写返回值类型,构造方法执行之后java程序自动返回值;

4)当一个类中没用定义任何构造方法的话,系统默认给该类提供一个无参数的构造方法,这个构造方法被称为缺省构造器

5)当一个类显示的将构造方法定义出来了,那么系统不再默认提供的缺省构造器了,建议开发中手动的为当前类提供无参数的构造方法;

6)构造方法支持重载机制,在一个类中编写多个构造方法,这多个构造方法显然已经构成方法重载机制;

public class Code{
	public static void main(String[] args){
		User u1 = new User("Jack");
		User u2 = new User(10);
	}
}

public User(int i){
	System.out.println("带有int参数类型的构造器")
}
public User(String name){
	System.out.println("带有String参数类型的构造器")
}

8.4 方法有无static方法的调用

方法有static修饰时,调用方法时不需要new对象,直接通过方法名(实参)/类名.方法名(实参)调用;

public class Code{
	public static void main(String[] args){
        Code.dosome();
        dosome;
    }
}
public ststic void dosome(){
	System.out.println("do some");
}

方法没有static修饰时,调用方法时需要new对象;

public class Code{
	public static void main(String[] args){
        Code t = new Code();
        t.dosome;
    }
}

public void dosome(){
	System.out.println("do some");
}

8.5 构造方法的作用

1)创建对象;

2)初始化实例变量的内存空间,赋值;

注意:
实例变量的系统默认赋值不是在类加载的时候完成赋值的,类加载的时候只将代码片段加载到了方法区内存,而实例变量的初始化是在创建对象之后(构造方法完成之后)完成初始化的

8.6 自动构造方法的快捷方式

单击右键—>Source—>Generate Constructor using Fields…

在这里插入图片描述

8.7 面向对象的封装以及构造方法的实例

public class helloworld{
	public static void main(String[] args){
		Bank b = new Bank("Jack",1000);
		System.out.println("账号名字为" + b.getName());
		System.out.println("账号余额为" + b.getMoney());
         Bank a = new Bank();
         System.out.println("账号名字为" + a.getName());
		System.out.println("账号余额为" + a.getMoney());
    }
}
class Bank{
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getMoney() {
		return money;
	}
	public void setMoney(int money) {
		this.money = money;
	}
	private String name;
	private int money;
    //无参数的构造器
    public Bank(){
	}
    //有参数的构造器
	public Bank (String s,int d) {
		name = s;
		money = d;
	}
}

09、this

9.1 this关键字的定义和性质

1)this是一个关键字 / 引用 / 变量,this变量中保存了内存地址表示自身,this存储在JVM堆内存java对象内;

2)创建100个java对象,每一个对象都有this,也就是说有100个不同的this;

3)this可以出现在“实例方法”当中,this指向当前正在指向这个动作的对象。【this代表当前对象】;

4)this在多数情况下都是可以省略不写的;

5)this在区分局部变量和实例变量的时候,"this."不能省;

public void setName(String name) {
		this.name = name;
	}
//“=”前面的this.name是实例变量
//“=”前面的name是局部变量,是形式参数

6)this不能使用在带有static的方法当中;

9.2 实例方法与实例变量

9.2.1 实例方法的访问(不带static的方法)

public class helloworld {
	public static void main(String[] args) {
		// 创建Customer对象
		Customer c1 = new Customer();
		c1.name = "zhangshan";
		// c1购物
		c1.shopping();

		// 创建Customer对象
		Customer c2 = new Customer();
		c2.name = "lisi";
		// c2购物
		c2.shopping();
	}
}

class Customer {
	// 姓名
	String name;

	// 构造方法
	public Customer() {
	}
    
	//实例方法
	public void shopping(){
		//当张三在购物的时候输出"张三在购物"
    	//当李四在购物的时候输出"李四在购物"
    	System.out.println(this.name + "在购物");
	}
}

在这里插入图片描述

1.2.2 实例变量的访问(不带static的变量)

public class helloworld {
	public static void main(String[] args) {
        //访问"当前对象"的num属性
        
  		//System.out.println(num); //编译错误(因为num是一个实例变量,需要"引用."的方式访问)
        
        //如何访问num?
        //创建一个对象
        ThisTest tt = new ThisTest();
        System.out.println(tt.num);
    }
}

class ThisTest{
	//实例变量
	int num = 10;
}

9.3 静态方法

1)静态方法(带有static的方法)访问的时候采用 类名.方法名,不能用this;

2)静态方法中不能"直接"访问实例变量和实例方法;(实例变量和实例方法都需要对象的存在);

3)静态方法中没有this,也就是说"当前对象"不存在,自然也无法访问当前对象的实例变量和实例方法(this代表的是当前正在执行这个动作的对象);

4)静态方法,既可以采用类名的方式访问,也可以采用应用的方式访问,但是即使采用引用的方式访问,实际上执行的时候和引用指向的对象无关,还是默认成“类名.”的方式访问,且会产生警告,但不会产生空指针异常;

9.4 特例:实例方法中实例方法的访问

实例方法和静态方法的访问的比较

public class ThisTest{
	public static void main(String[] args){
		//ThisTest.doSome();
    	//编译错误(实例方法必须先创建对象,通过引用.的方式访问)如下:
    	ThisTest tt = new ThisTest();
    	tt.run();
       	
    	doSome();//带有static的方法,可以通过类名.的方式直接访问
    }
    public static void doSome(){
		System.out.println("do some!");
    }
    public void doOther(){
		System.out.println("do other");
    }
    //特例:实例方法中实例方法的访问
    public void run(){
		System.out.println("run execute!");
    	doOther();//this.doOther
        //这里可以直接写“doOther();”由于是通过run()来访问到doOther的,此时this就是访问run()时的对象
    }
}

9.5 实例方法和实例变量的定义和访问的比较

不带有static关键字的方法被称为"实例方法";

不带有static关键字的变量被称为"实例变量";

public class ThisTest{
	public static void main(String[] args){
        //编译错误
        /*System.out.println(name);
        doSome();
        
        System.out.println(this.name);
        this.doSome();*/
        
        //编译通过
        ThisTest tt = new ThisTest();
        System.out.println(tt.name);
        tt.doSome();
    }
    //实例变量
    String name;
    //实例方法
    public void doSome(){
        System.out.println("do some!");
	}
}

9.6 this的作用领域

1)可以使用在实例方法中,代表当前对象【语法格式:this】

2)可以使用在构造方法中,通过当前的构造方法调用其他的构造方法【语法格式:this(实参)】;

3)this()这种语法只能出现在构造方法的第一行;

使用在构造方法中,通过当前的构造方法调用其他的构造方法的代码如下:

public class helloworld {
	public static void main(String[] args) {
		Date d = new Date();
		System.out.println(d.getYear() + "-" +  d.getMonth() + "-" + d.getDay());
		Date a = new Date(2021,1,3);
		System.out.println(a.getYear() + "-" +  d.getMonth() + "-" + d.getDay());
	}
}

class Date{
	private int year;
	private int month;
	private int day;
	
	public Date(int year, int month, int day) {
		this.year = year;
		this.month = month;
		this.day = day;
	}
	
	public Date() {
		//需求:当程序员调用以下无参数的构造方法的时候,默认创建日期为1970.1.1
		
		/*this.year = 1970;
		this.month = 1;
		this.day = 1;*/
		
		//以上代码可以通过调用另一个构造方法来完成
		//但前提是不能通过创新新的对象。以下代码表示创新了一个新的对象
		//new Date(1970.1.1);
		
		//需要采用以下的语法来完成构造方法的调用
		this(1970,1,1);
	}
	
	public int getYear() {
		return year;
	}

	public void setYear(int year) {
		this.year = year;
	}

	public int getMonth() {
		return month;
	}

	public void setMonth(int month) {
		this.month = month;
	}

	public int getDay() {
		return day;
	}

	public void setDay(int day) {
		this.day = day;
	}

}

9.7 两种方法调用以及实例变量的访问的完整/省略写法

public class Test{
	
	//没有static的变量
	int i = 10;
	
	//带有static的方法
	public static void doSome() {
		System.out.println("do some!");
	}
	
	//没有static的方法
	public void doOther() {
		System.out.println("do other!");
	}
	
	//带有static的方法
	public static void method1() {
		//调用doSOme(带有static的方法)
		//完整方法的调用
		Test.doSome();
		//省略方法的调用
		doSome();
		
		//调用doOther(没有static的方法)
		//完整方法的调用
		Test t = new Test();
		t.doOther();
		//省略方法的调用
		//无
		
		//访问i(实例参数)
		//完整方法的调用
		System.out.println(t.i);
		//省略方法的调用
		//无
	}
	
	
	//没有static的方法
	public void method2() {
		//调用doSOme(带有static的方法)
		//完整方法的调用
		Test.doSome();
		//省略方法的调用
		doSome();//this doSome();
			
		//调用doOther(没有static的方法)
		//完整方法的调用
		this.doOther();//调用的doOther中无static,且当前方法中也无static,当前方法有this,所以直接引用.即this.doOther()
		//省略方法的调用		
		doOther();
		
		//访问i(实例参数)
		//完整方法的调用
		System.out.println(this.i);
		//省略方法的调用
		System.out.println(i);
	}
	//主方法
	public static void main(String[] args) {
		//要求在这里编写程序调用method1(带有static的方法)
		//完整方法的调用
		Test.method1();
		//省略方法的调用
		method1();
		
		//要求在这里编写程序调用method2(没有static的方法)
		//完整方法的调用
		Test t = new Test();
		t.method2();
		//省略方法的调用
		//无
	}
}

10、static

10.1 static关键字的定义和性质

1)static翻译为"静态的";

2)static修饰的方法是静态方法,static修饰的变量是静态变量;

3)使用static修饰的元素都称为静态的,都可以用"类名."的方式访问,当然也可以用"引用."的方式访问【但不建议】

4)采用"引用."的方式访问的时候,即使引用是null,也不会出现空指针异常,因为访问静态数据不需要对象的存在;

10.2 实例变量与静态变量

10.2.1 实例变量

什么时候成员变量声明为实例变量呢?

–所有对象都有这个属性,但是这个属性的值会随着对象的变化而变化【不同对象的这个属性具体值不同】

–实例变量在构造方法进行的时候初始化,存在堆内存中

以下列例子说明:

public class helloworld {
	public static void main(String[] args) {
        Chinese zhangsan = new Chinese("1","zhangsan","Chinese");
        System.out.println(zhangsan.country);
	}
}
class Chinese{
	String id;
	String name;
	String country;
	public Chinese(String id, String name, String country) {
		this.id = id;
		this.name = name;
		this.country = country;
	}
}

在这里插入图片描述

10.2.2 静态变量

什么时候成员变量声明为静态变量呢?

–所有对象都有这个属性,并且所有对象的这个属性的值是一样的,建议定义为静态变量,节省内存的开销

**静态变量在类加载的时候初始化,内存在方法区中开辟。**访问的时候不需要创建对象,直接使用"类名.静态变量名"的方式访问;

补充:

  • 局部变量存储在栈内存当中;
  • 实例变量在构造方法进行的时候初始化,存在堆内存中(成员变量的一种)
  • 静态变量在类加载的时候初始化,存在方法区内存中(成员变量的一种)

在这里插入图片描述

以下列例子说明:

public class helloworld {
	public static void main(String[] args) {
        Chinese zhangsan = new Chinese("1","zhangsan");
        System.out.println(zhangsan.country);
        System.out.println(Chinese.country);
        zhangsan = null;
        System.out.println(zhangsan.country);
	}
}
class Chinese{
	String id;
	String name;
	static String country = "chinese";
	public Chinese(String id, String name) {
		this.id = id;
		this.name = name;
	}
}

在这里插入图片描述

输出结果为三个Chinese;

1)所有静态的数据都是可以采用"类名.“,也可以采用"引用.”,但是建议采用类名.的方式访问;

2)采用"引用."的方式访问时,即使是null,也不会出现空指针异常,因为访问静态变量的时候不需要对象的存在;

10.3 静态代码块

1)语法格式:

static{
	//java语句
}

2)静态代码块在类加载时执行,并且执行一次

3)静态代码块在一个类中可以编写多个,并且遵循自上而下的顺序依次执行;

4)静态代码块可以用在项目中要求在类加载的时刻/时机执行代码完成日志的记录,那么这段记录日志的代码就可以编写在静态代码块当中,完成日志记录;

5)静态代码块是java为程序员准备一个特殊的时刻,这个时刻被称为类加载时刻,若希望在此刻执行一段特殊的程序,这段代码可以放到静态代码块当中;

public class StaticTest{
	static{
		System.out.println("类加载--->1");
    }
    static{
		System.out.println("类加载--->2");
    }
}

10.4 *实例语句块 / 代码块

1)实例代码块可以编写多个,也是遵循自上而下的顺序依次执行;

2)实例代码块在构造方法执行之前执行,构造方法执行一次,实例代码块对应执行一次;

3)实例代码块也是java语言为程序员准备一个特殊的时机,这个时机被称为:对象初始化时机

public class helloworld{
    public class Test{
    //构造函数
    	public Test(){
    		System.out.println("Test类的缺省构造器执行");
    	}
    }    
    //实例代码块
    {
		System.out.println(1);
    }
    //实例代码块
    {
		System.out.println(2);
    }
    public static void main(String[] args){
    	System.out.println("main begin");
    	new helloworld();
	}
}

10.5 static总结

public static void main(String[] args)

10.5.1 对java语句的解读

1)public代表公开的,在任何位置都可以访问;

2)static表示静态的,使用"类名."的方式访问,不需要创建对象

3)void表示main方法执行结束之后不返回任何值;

4)(String[] args)是参数列表;

10.5.2 什么时候定义为静态的?

1)方法描述的是动作,当所有的对象执行这个动作的时候,最终产生影响是一样的,那么这个动作已经不再属于某一个对象动作了,可以将这个动作提升为类级别的动作,模板级别的对象;

2)静态方法中无法直接访问实例变量和实例方法;

3)大多数方法都定义为实例方法,一般一个行为或一个动作在发生的时候都需要对象的参与而大多数“工具类”当中的方法都是静态的,因为工具类就是方便编程的,为了方便方法的调用,自然不需要new对象是最好的;


11、final

表示:最终的,不可变的

  • final修饰的类无法被继承
  • final修饰的方法无法被覆盖
  • final修饰的变量不可二次赋值
  • final修饰的实例变量必须手动赋值,不能采用系统默认值;
//方法一:
final int age = 10;
//方法二:
final int age;
public Text(){
	this.age = 10;
}//其实本质上是一种方式,都是在构造方法中给实例变量赋值
  • final修饰的引用

    1)一旦指向某个对象后,不能指向别的对象,被指向的对象不能被垃圾回收器回收;

    2)虽然指向某个对象后不能指向别的对象,但是所指的对象的内存是可以被修改的

final User user = new User(30);
user = new User(5);//一旦指向某个对象后,不能指向别的对象
user.id = 50;//内存可以被修改

12、package

1)引入包这个机制为了方便程序的管理,不同的功能的类被分门别类放到不同的软件包中,查找比较方便,管理比较方便,易维护;

2)在java源程序的第一行上编写package语句,package只能编写一个语句;

3)语法结构:
package 包名;

4)包名的命名规范:
公司域名倒叙 + 项目 + 模块名 + 功能名;
e.g. com.bjpowernode.oa.user.service;(company)
org.apache.tomcat.core;(orgnization)

5)包名要求全部小写,包名也是标识符,必须遵循标识符命名规范;

6)一个包将来对应的是一个目录;

7)使用package机制之后,类名是:包名.类名


13、import

1)import语句用来导入其他类,同一个包下的类不需要导入

2) import语法格式
import 类名;
import 包名.*;

e.g.:调包Scanner

import java.util.Scanner;

import java.utill.*

使用Scanner

Scanner s = new Scanner(System.in)

3)import语句需要编写在package语句之下,class语句之上;

*java.lang.不需要手动引入,系统自动引入;

lang:language语言包,是java语言的核心类

String(java.lang.String)

4)eclipse导入类的快捷键Ctr + Shift + o


14、super

14.1 super和this的共同特征

1)都能出现在实例方法和构造方法中

2)“super.” “super()” “this.” “this()”

3)不能使用在静态方法中

4)大多数情况下可以省略

5)只能出现在构造方法的第一行

14.2 super和this不同的特征

14.2.1 关于this关键字

1)在区分局部变量和实例变量的时候不能省略;

public void setName(String name){
	this.name = name;
}

2)this()通过当前的构造方法去调用**“本类”**中的其他构造方法,目的是:代码复用

14.2.2 关于super关键字

1)super(实参列表)通过当前的构造方法去调用**“父类”**中的构造方法,目的是:创建子类对象的时候,先初始化父类型特征,实现代码复用

public class Super {
    public static void main(String[] args) {
        new B();
    }
}
class  A{
    public A() {
        System.out.println("A类的构造方法!");
    }
}

class B extends A{
    public B(){
        super();//子类构造方法的第一行无论写不写都会默认存在super(),但不与this()共存;
        System.out.println("B类中的构造方法");
    }
}

2)重要结论:
当一个构造方法的第一行:
既没有this()又没有super()【this()和super()不能共存】的话,默认会有一个super();
表示通过当前子类的构造方法调用父类的无参数构造方法,所以必须保证父类的无参构造方法是存在的;

public class Super {
    public static void main(String[] args) {
        new B();
    }
}
class  A{
    public A() {
        System.out.println("A类的构造方法!");
    }
}

class B extends A{
    public B(){
        this("zhangsan");//此处调用下面有参的构造方法,同时也会触发super()调用父类的构造方法
        System.out.println("B类中的构造方法");
    }
    public B(String name){
        super();//无论如何,构造方法中都会存在一个super()
        System.out.println("B类中的有参数构造方法String");
    }
}

在这里插入图片描述

3)理解:super的作用:模拟现实世界要想有儿子,必须把父亲造出来;它代表的是当前对象(this)的父类型特征;

4)无论怎么折腾,父类的构造方法都会先执行

不管创建什么对象,老祖宗的object类的无参构造方法一定会执行(object类中的构造方法是处于"栈顶部",最后调用最先结束)

5)super不是引用不保存内存地址也不指向任何对象,只是代表当前对象内部那一刻父类型的特征;

6)"super."后面不仅可以访问属性,还可以访问方法;

7)练习

public class Super {
    public static void main(String[] args) {
        new C();
    }
}

/*class Object{
	public Object(){
	}
}*/

class  A /*extends Object*/{//Object这个是Sun公司写的
    public A() {
        //有super()
        System.out.println("1");
    }
}

class B extends A{
    public B(){
        //有super()
        System.out.println("2");
    }
    public B(String name){
        //有super()
        System.out.println("3");
    }
}

class C extends B{
    public C(){
        this("zhangsan");
        System.out.println("4");
    }
    public C(String name){
        this(name,20);
        System.out.println("5");
    }
    public C(String name,int age){
        super(name);
        System.out.println("6");
    }
}

输出结果在这里插入图片描述

14.3 何时使用,何时省略super关键字?

​ 1)何时使用super(实参列表)
​ 当子类中构造方法访问父类private修饰的实例变量时,此时无法访问,必须通过super(实参列表)调用父类的构造方法才可访问父类private修饰的实例变量;

​ 2)初始化当前对象父类型的特征,并没有创新新的对象,实际上对象只创建一个;

​ 3)"super."何时不能省略?
​ 父中有,子中又有,如果想在在子中访问"父的特征"时不可以省略

public class Super {
    public static void main(String[] args) {
        Vip v = new Vip("zhangsan");
        v.shopping();
    }
}
class Customer{
    String name;//相当于super.name
    public Customer(){

    }
    public Customer(String name){
        super();
        this.name = name;
    }
}
class Vip extends Customer{
    String name;//相当于this.name	允许同名变量出现,此时的name为空,但super和this访问的name不同
    public Vip(){

    }
    public Vip(String name){
        super(name);
    }
    public void shopping() {
        System.out.println(this.name + "正在购物!");//null
        System.out.println(super.name + "正在购物!");//zhangsan
        System.out.println(name + "正在购物!");//null
    }
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Duw4oiT1-1657728924920)(C:\Users\86177\Pictures\Saved Pictures\微信图片_20220107192411.png)]

15、方法覆盖

1)方法覆盖又称为方法重写(override【官方的】/overwrite)

2)什么时候使用方法重写?

	*	当父类中的方法已经无法满足当前子类的业务需求;
	*	子类中有必要将父类中的继承过来的方法进行重新编写;

3)什么条件满足之后会发生方法重写呢?

  • 方法重写发生在具有继承关系的父子类之间;
  • 方法重写的时候:返回值类型相同,方法名相同,形式参数列表相同;
  • 方法重写的时候:访问权限不能更低,可以更高;(指public相关的修饰词)
  • 方法重写的时候:抛出异常不能更多,可以更少;

4)注意:

  • 私有方法不能继承,所以不能覆盖;
  • 构造方法不能继承,所以不能覆盖;
  • 静态方法不存在覆盖;
  • 覆盖只针对方法,不谈属性;

5)eclipse快速重写

在这里插入图片描述


16、常量

1) final修饰的实例变量一般和static联合使用,称为常量

2)java规范中要求所有变量的单词全部大写,每个单词之间使用下划线连接;

public static final String GUO_JI = "中国";

public static final double PI = 3.1415926;


17、访问控制权限修饰符

1)作用:控制元素的访问范围

2)访问控制权限修饰符包括:
public 表示公开的, 在任何位置都可以访问;
protected 表示受保护的,在同包下、子类可以访问
default(缺省) 不写 在同包下可以访问
private 表示私有的, 在本类中访问;【内部类除外】

3)修饰符范围:
private < 缺省 < protected < public

4)属性(四个都能用)

方法(四个都能用)

类(public和默认都能用,其他不行)

接口(public和默认都能用,其他不行)

18、抽象类

18.1 什么是抽象类?

18.1.1 对抽象类的理解

在这里插入图片描述

18.1.2 关于抽象类

  • 类与类之间具有共同特征,将这些共同特征提取出来,形成的就是抽象类;
  • 类本身是不存在的,属于抽象类无法创建对象【无法实例化】;
  • 抽象类是用来被子类继承的
  • finial关键字和abstract关键字不能同时出现;
  • 抽象类的子类可以是抽象类;
  • 抽象类虽然无法实例化,但有构造方法,这个构造方法是供子类使用的;
  • 接口一般描述的是行为动作信息
  • 一个非抽象的类继承抽象类,必须把抽象类中的抽象方法给实现(覆盖、重写)了
public class HelloWorld{
	public static void main(String[] args){
        //如何实现多态呢???
        Animal a = new Bird();//向上转型(自动类型转换)
        //面对抽象对象编程,降低程序的耦合度,提供程序的扩展力,符合OCP原则
	}
}
abstract class Animal{
	public abstract void move();
}
class Bird extends Animal{
	public void move(){
	}//Bird不是抽象类,必须实现父类的抽象方法
}//如果Bird是抽象类的话,那么继承过来的抽象方法可以不去重写、覆盖、实现

18.2 抽象类属于什么类型?

抽象类也属于引用数据类型;

18.3 抽象类怎么定义?

[修饰符列表] abstract class 类名{
类体;
}

18.4 抽象方法

1)抽象方法表示没有实现的方法,没有方法体以分号结尾的方法。例如:

public abstract void doSome();

2)抽象类中不一定有抽象方法,但抽象方法一定在抽象类当中;

3)没有方法体的方法不一定都是抽象方法,Object类中就有很多方法都没有方法体,以" ;"结尾
e.g.:public native int hashCode();这个方法底层调用了C++写的动态链接库程序;前面修饰符列表中有native,表示调用JVM本地程序


19、接口

19.1 关于接口

1)接口也是一种引用数据类型,

2)接口的完全抽象的(抽象类是半抽象类)或者也可以说接口是特殊的抽象类

3)接口支持接口继承也支持接口多继承

interface A{
}
interface B{
}
interface C extends A,B{
}

4)接口中只包含两部分内容,一部分是常量,另一部分是抽象方法,所有内容都是public修饰的,都是公开的;

5)接口中抽象方法中的public static 可以省略,"public abstract int sun(int a,int b);" ——> "int sun(int a,int b);"

6)接口中**变量中的public static final **可以省略,”public static final double PI = 3.1415926;" —> "double PI = 3.1415926;;"

7)接口中的方法都是抽象方法,所以接口中的方法都没有方法体

19.2 接口怎么定义?

[修饰符列表] interface 接口名{

}

19.3 接口基础语法

1)类和类之间叫做继承,类和接口之间叫做实现(可看作继承),用关键字"implements";

2)当一个非抽象的类实现接口的话,必须将接口中所有的抽象方法全部实现(覆盖、重写);

public class interface {
    public static void main(String[] args) {
        //如何实现多态???
        //父类型的引用指向子类型的对象
        MyMath m = new MyMathImp();
        //调用接口里面的方法(面向接口编程)
        int result = m.sum(10,2);
        System.out.println(result);
    }
}
interface MyMath{
    double PI = 3.1415926;
    int sum(int a,int b);
    int sub(int a,int b);
}
class MyMathImp implements MyMath{
    public int sum(int a,int b){//重写接口中的抽象方法
        return a + b;
    }
    public int sub(int a,int b){//重写接口中的抽象方法
        return a - b;
    }
}

注意:非抽象的类实现接口时重写的抽象方法public不可省;

3)一个类可以实现多个接口,这种机制弥补了"java中类和类只支持单继承"带来的缺陷;

接口和接口之间在进行强制类型转换的时候,没有继承关系,也可以强转,但运行的时候可能会出现ClassCastException异常,需要加instanceof进行判断;

public class HelloWorld{
    public static void main(String[] args) {
        //如何实现多态???
        A a = new C();
        if(a instanceof B){
            B b2 = (B)a;//此时a b的底层都是C,C实现了接口A和接口B,所以可以向下转型
            b2.m2();
        }
        
        
        M m = new E();
        if(m instanceof K){
            K k = (K)m;//这里的E()和K没有关系,E实现了M,但没有实现接口K,所以不能向下转型
            k.m3();
        }
    }
}
interface A{
    void m1();
}
interface B{
    void m2();
}
class C implements A,B{//C实现了A和B
    public void m1(){

    }
    public void m2(){
        System.out.println("可以向下转型!");
    }
}

interface K{
    void m3();
}
interface M{
    void m4();
}
class E implements M{//E实习了M,但没有实现K
    public void m3(){
    }
    public void m4(){
    }

4)继承和实现都存在的话,代码怎么写?

extends关键字在前,implements关键字在后

public class interface{
	public static void main(String args[]){
		//创建对象
        Flyable f = new Cat();
        f.fly();
	}
}
//动物类:父类
class Animal{
}
//可飞翔的接口(是一对翅膀)
//能插拔的就是接口。
//接口提取的是行为动作
interface Flyable{
	void fly();
}
//动物类子类:猫
//Flyable是一个接口,是一个翅膀的接口,通过接口插到猫身上,让猫可以飞翔
class Cat extends Animal implements Flyable{
	public void fly(){
		System.out.println("猫会飞");
    }
}

19.4 接口在开发的作用

类似于多态在开发中的作用;

  • 多态:面向抽象编程(面向接口编程),不要面向具体编程。降低程序的耦合度,提高程序的扩展力,符合OCP的开发原则;
  • 接口的使用离不开多态机制(接口+多态才可达到解耦合);
  • 接口可以解耦合,解的是调用者实现者的耦合;
  • 调用者面向接口调用,实现者面向接口实现

以去餐馆吃饭为例:(重点)

接口是抽象的,菜单是一个接口(菜单上有一个抽象的照片:西红柿炒鸡蛋)

谁面向接口调用?(顾客面向菜单点菜,调用接口)

谁负责实现这个接口呢?(后台的厨师负责把西红柿炒鸡蛋做好,是接口的实现者)

这个接口有什么用呢?(有这个饭馆的"菜单",让“顾客”和“后厨”解耦合了,他们完全依靠这个抽象的菜单沟通)

public class Super {
    public static void main(String[] args) {
        //创建厨师对象
        Meau c1 = new ChineseCook();
        //创建顾客对象
        Customer customer = new Customer(c1);
        //顾客点菜
        customer.order();
    } 
}
interface Meau{
    void ChaoDan();
    void RouSi();
}
class Customer{
    //Customer has a Meau!顾客手里有一个菜单
    //实例变量:属性
    private Meau meau;
    //提供点菜的方法
    public void order(){
        //调用get方法或直接访问先拿菜单
        //Meau m = this.getMeau();
        //m.ChaoDan();
        //m.RouSi();
        meau.RouSi();
        meau.ChaoDan();
    } 

    public void setMeau(Meau meau) {
        this.meau = meau;
    }

    public Meau getMeau() {
        return meau;
    }

    public Customer() {
    }

    public Customer(Meau meau) {
        this.meau = meau;
    }
//如果以下这么写就写死了,焊死了,没有可插拔了
    //ChineseCook c1;
    //JapaneseCook c2;
}
class ChineseCook implements Meau{
    public void ChaoDan(){
        System.out.println("中餐师傅做炒蛋");
    }
    public void RouSi(){
        System.out.println("中餐师傅做肉丝");
    }
}
class JapaneseCook implements Meau{
    public void ChaoDan(){
        System.out.println("日本师傅做炒蛋");
    }
    public void RouSi(){
        System.out.println("日本师傅做肉丝");
    }
}

19.5 抽象类和接口的语法区别

抽象类是半抽象的;
接口是完全抽象的;

抽象类中有构造方法;
接口中没有构造方法;

接口和接口之间支持多继承;
一个抽象类只能继承一个类(单继承);

接口中只允许出现常量和抽象方法;

注意:以后接口使用的比抽象类多,接口一般都是对“行为”的抽象


20、关于Object类

20.1 什么是ApI?

  • 应用程序编程接口;
  • 整个JDK的类库就是一个javase的API;
  • 每一个API都会配置一套API帮助文档;
  • SUN公司提前写好的这套类库就是API(一般每一份API都对应一份API帮助文档);

20.2 Object类中的方法

protected Object clone() //负责对象克隆的

int hashCode() //获取对象哈希值的一个方法

boolean equals(Object obj) //判断两个对象是否相等

String toString() //将对象转换成字符串形式

protected void finalize() //垃圾回收器负责调用的方法

20.3 关于toString方法

1)源代码

public String toString(){
	return this.getClass().getName() + "@" + Integar.toHexString(hashCode());
}
//源代码上toString()方法的默认实现是:
//类名@对象的内存地址转换为十六进制的形式

2)作用:

调用toString方法可以将一个"java对象"转换成字符串表示形式

3)建议所有子类都去重写toString()方法,toString()方法应该是一个简洁的、详实的、易阅读的

public class Hello{
    public static void main(String[] args) {
        Time t1 = new Time(1970,1,1);
        String s1 = t1.toString();
        System.out.println(s1);
        //System.out.println(t1);
    }
}
class Time{
    int year;
    int month;
    int day;
    public Time(){

    }
    public Time(int year, int month, int day) {
        this.year = year;
        this.month = month;
        this.day = day;
    }
    //重写之前:输出Time@a09ee92
    public String toString(){
        return this.year + "年" +this.month+ "月" + this.day + "日";
    }//重写之后:输出1970年1月1日
}

20.4 关于equals方法

1)源代码

public boolean equals(object obj){
	return (this == obj);
}

以上这个方法是Object类的默认实现,默认采用判断两个java对象是否相等,而判断的是java对象的内存地址是否相等,需要重写equals

2)作用:

判断两个java对象是否相等

3)代码表示

public class Hello{
    public static void main(String[] args) {
        Time t1 = new Time(2008,8,8);
        Time t2 = new Time(2008,8,8);
        System.out.println(t1 == t2);//这是比较的是两个对象保存的内存地址是否相等?
        boolean b = t1.equals(t2);
        System.out.println(b);
        //System.out.println(t1.equals(t2));
    }
}
class Time {
    int year;
    int month;
    int day;

    public Time() {

    }

    public Time(int year, int month, int day) {
        this.year = year;
        this.month = month;
        this.day = day;
    }

    //重写equals方法
    public boolean equals(Object obj) {
        //如果obj为空,如果obj不是Time类型没必要比较,直接返回false
        if (obj == null||!(obj instanceof Time))
            return false;
        //如果obj保存的地址相同没必要比较,直接返回true
        if (this == obj) {
            return true;
        }
        //这里直接向下转型,obj一定是Time类型
        Time t = (Time) obj;
        return this.year == t.year && this.month == t.month && this.day == t.day;
    }
}

4)String类已经重写了equals和toString方法,String中存在构造方法且字符串比较不能用"=="

5)基本数据类型比较能使用"==",所有的引用数据类型比较需要调用equals方法;

//如果只是普通定义
String a = "添砖JAVA";
String b = "添砖JAVA";
//则可以通过==来判断也可以用equals方法

String c = new String("添砖JAVA");
String d = new String("添砖JAVA");
//若通过创建对象,则只能用equals,这里比较的是对象地址
public class Hello{
    public static void main(String[] args) {
        User u1 = new User("zhangsan",new Address("北京","大兴区","1111"));
        //上面一行代码与下面两行等效
        //Address addr = new Address("北京","大兴区","1111");
        //User u = new User("zhangsan",addr);
        User u2 = new User("zhangsan",new Address("北京","大兴区","1111"));
        System.out.println(u1.equals(u2));
    }
}
class User{
    String name;
    Address addr;

    public User(String name, Address addr) {
        this.name = name;
        this.addr = addr;
    }

    public User() {
    }

    public boolean equals(Object obj) {
        if (obj == null || !(obj instanceof User)) return false;
        if (this == obj) return true;
        User u = (User) obj;
        return this.name.equals(u.name) && this.addr.equals(u.addr);
    }
}
class Address{
    String city;
    String street;
    String zipcode;

    public Address(String city, String street, String zipcode) {
        this.city = city;
        this.street = street;
        this.zipcode = zipcode;
    }

    public Address() {
    }
    public boolean equals(Object obj) {
        if (obj == null || !(obj instanceof Address)) return false;
        if (this == obj) return true;
        Address v = (Address) obj;
        return this.city.equals(v.city) && this.street.equals(v.street) && this.zipcode.equals(v.zipcode);
    }
}

20.5 关于finalize()方法

1)源代码

protected void finalize() throws Throwable{	}

2)finalize()方法只有一个方法体里面没有代码,而且这个方法是protected修饰的;

3)这个方法不需要程序员手动调用,JVM的垃圾回收负责调用这个方法;

4)finalize()方法实际上是SUN公司为java程序员准备的一个时机,垃圾销毁时机,如果希望在对象销毁的时机执行一段代码的话,这段代码要写到finalize()方法当中;

5)

public class Gc {
    public static void main(String[] args) {
        Peason p = new Peason();
        p = null;
    }
}
class Peason{
    protected void finalize() throws Throwable{
        System.out.println("对象垃圾即将被销毁!!!");
    }
}

java中的垃圾回收器不是轻易启动的,垃圾太少,或者时间没到,种种条件下可能启动也可能不启动;

System.gc();//可以建议垃圾回收器启动,但不一定启动;

20.6 关于hashCode方法

1)源代码

public native int hashCode();

2)这个方法不是抽象方法,带有native关键字,底层调用C++程序;

3)hashCode()方法返回的是哈希码;

实际上就是一个java对象的内存地址,经过哈希算法得出一个值,所以hashCode()方法的执行结果可以等同看做一个java对象的内存地址

4)

public class HashCode{
    public static void main(String[] args) {
    	Object o = new Object();
        int hashCOdeValue = o.hashCode();
        System.out.println(hashCodeValue);
    }
}

21、内部类

21.1 定义

内部类:在类的内部又定义了一个新的类,被称为内部类

22.2 内部类的分类

静态内部类:类似于静态变量;

实例内部类:类似于实例变量;

局部内部类:类似于局部变量;匿名内部类属于局部内部类的一种(没有名字)

22.3 代码解释

class Test{
	//静态内部类
	static class Inner1{
	}
	//实例内部类
	class Inner2{
	}
	public void doSome(){
		//局部变量
		int i = 10;
		//局部内部类
		class Inner3{
		}
	}
    public void doOther(){
        new Test.new Inner2//这样使用
        //doSome()方法中的内部类Inner3,在doOther()中不能用
    }
}

使用内部类编写的代码可读性很差

22.4 匿名内部类

是局部内部类的一种,没有名字

public class Test {
    public static void main(String[] args) {
        MyMath mm = new MyMath();
        //ComputerImp c = new ComputerImp()
        //mm.mySum(c,100,200);
        //以上两行代码可以直接换成下面一行
         mm.mySum(new ComputerImp(),100,200);
    }
}
//负责计算的接口
interface Computer{
    //抽象方法
    int sum(int a,int b);
}
//编写一个Computer接口的实现类用来创建对象
class ComputerImp implements Computer{
    //对方法的实现
    public int sum(int a,int b){
        return a + b;
    }
}
//数学类
class MyMath{
    //数学求和方法
    public void mySum(Computer c,int x,int y){
        int retValue = c.sum(x,y);
        System.out.println(x + "+" + y + "=" + retValue);
    }
}

使用匿名内部类之后

public class Test {
    public static void main(String[] args) {
		MyMath mm = new MyMath();
		mm.mySum(new Computer(){
            int sum(int a,int b){
                return a + b;
            }
        },100,200);//这里并不是接口可以直接new了,中间的{}代表了对接口的实现
    }
}
interface Computer{
    int sum(int a,int b);
}
class ComputerImp implements Computer{
    //对方法的实现不用写了,用匿名内部类实现
}
//数学类
class MyMath{
    //数学求和方法
    public void mySum(Computer c,int x,int y){
        int retValue = c.sum(x,y);
        System.out.println(x + "+" + y + "=" + retValue);
    }
}

不建议用匿名内部类,因为没有名字,没办法重复使用,代码太乱,可读性太差

注意:使用IDEA自动写匿名内部类

mm.mySum(new Computer(){},写完这个之后,需要纠正错误:

光标移动到红色下划线下面,快捷键:Alt + 回车

继承、关联、实现的使用场景

is a:继承
Cat is a Animal;(猫是一个动物)
凡是满足is a的表示都可以设置为“继承”;
A extends B
has a:关联
I has a Animal;(我有一支笔)
凡是能够用has a来描述的,统一以“属性(关联)”的方式存在;
A{
	B b;
}
like a:实现
Cook like a FoodMeau;(厨师像一个菜单一样)
凡是能够满足like a关系的表示类“实现”接口;
A implement B;

22、java程序基础练习题

22.1 题目一:Vehicle driving

要求:

请定义一个交通工具(Vehicle)的类
其中有属性:
速度(speed),
体积(size),
方法移动(move()),
设置速度(setspeed(int speed,) ),
加速speedUp (),
减速speedDown(),
最后在测试类Vehicle中的main()中实例化一个交通工具对象并通过方法给它初始化speed,size的值并且打印出来,用加速减速的方法对速度进行改变。

public class HelloWorld {
    public static void main(String[] args) {
        //无参数构造方法创造对象
        Vehicle v = new Vehicle();
        //有参数构造方法创造对象
        Vehicle v1 = new Vehicle(100.0,5.0);
        //通过set方法赋值
        v.setSpeed(100.0);
        System.out.println("oldSpeed : " + v.getSpeed());
        v.setSize(5.0);
        //调用加速方法
        v.speedUp(10.0);
        System.out.println("addSpeed : " + v.getSpeed());
        //调用减速方法
        v.speedDown(5.0);
        System.out.println("downSpeed : " + v.getSpeed());
    }
}

class Vehicle {
    private double speed;
    private double size;
    //无参构造方法
    public Vehicle() {
    }
    //有参构造方法
    public Vehicle(double speed, double size) {
        this.speed = speed;
        this.size = size;
    }
    public double getSpeed() {
        return speed;
    }
    //设置速度的方法
    public void setSpeed(double speed) {
        this.speed = speed;
    }
    public double getSize() {
        return size;
    }
    public void setSize(double size) {
        this.size = size;
    }
    //交通工具的移动方法
    public void move() {
        System.out.println("公共汽车起步行驶");
    }
    //加速方法
    public void speedUp(double addSpeed) {
        //在原来基础上加
        //int oldSpeed = this.getSpeed()
        this.setSpeed(this.getSpeed() + addSpeed);
    }
    //减速方法
    public void speedDown(double delSpeed) {
        //在原来基础上减
        //int oldSpeed = this.getSpeed()
        this.setSpeed(this.getSpeed() - delSpeed);
    }
}

22.2 题目二:calculator

要求:

1)定义名为Number的类其中有两个整型数据成员n1和n2应声明为私有。
2)编写构造方法赋值n1和n2初始值;
3)为该类定义加addition()、减subration()、乘multiplication()、除division()公有实例方法;
4)分别对两个成员变量执行加、减、乘、除的运算;

public class JiSuanQi {
    public static void main(String[] args) {
        Number n1 = new Number();
        Number n2 = new Number(5,41);
        Number n3 = new Number(82,6);
        Number n4 = new Number(24,6);
        n1.addition();
        n2.subration();
        n3.multiplication();
        n4.division();
    }
}
class Number {
    private int n1;
    private int n2;

    public Number(int n1, int n2) {
        this.n1 = n1;
        this.n2 = n2;
    }

    public Number() {
        this(10,20);
    }

    public void setN1(int n1) {
        this.n1 = n1;
    }

    public void setN2(int n2) {
        this.n2 = n2;
    }

    public int getN1() {
        return n1;
    }

    public int getN2() {
        return n2;
    }

    public void addition(){
        System.out.println(n1 + "+" + n2 + "=" + (n1+n2));
        System.out.println(this.getN1() + "+" + this.getN2() + "=" + (this.getN1() + this.getN2()));
    }

    public void subration(){
        System.out.println(n1 + "-" + n2 + "=" + (n1-n2));
        System.out.println(this.n1 + "-" + this.getN2() + "=" + (this.getN1() - this.getN2()));
    }

    public void multiplication(){
        System.out.println(n1 + "*" + n2 + "=" + (n1*n2));
        System.out.println(n1 + "*" + n2 + "=" + (getN1() * getN2()));
    }

    public void division(){
        System.out.println(n1 + "/" + n2 + "=" + (n1/n2));
    }
}

22.3 题目三:People Message

要求:

1)定义一个人类People该类中应该有两个私有属性姓名name和年龄age;
2)定义构造方法用来初始化数据成员;
3)定义显示display方法将姓名和年龄打印出来;
4)在main方法中创建人类对象的实例然后将信息显示;

public class People {
    public static void main(String[] args) {
        Peason p = new Peason("Sam",18);
        p.display();
        Peason p2 = new Peason();
        p2.setName("张三");
        p2.display();
    }
}
class Peason{
    private String name;
    private int age;

    public void display(){
        System.out.println("name:" + this.getName() + "," + "age:" + this.age);
    }


    public Peason() {
    }

    public Peason(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public int getAge() {
        return age;
    }
}

22.4 题目四:Add Time

要求:

1)定义为MyTime的类其中应有三个整形成员时hour分minute秒second;
2)为了保证数据的安全性这三个成员变量应声明为私有;
3)为MyTime类定义构造方法以方便创建对象时初始化成员变量;
4)再定义display方法用于将时间信息打印出来;
5)为MyTime类添加一下方法:
addSecond(int sec)
addMinute(int min)
addHour(int hou)
subSecond(int sec)
subMinute(int min)
subHour(int hou)

public class Time {
    public static void main(String[] args) {
        MyTime t1 = new MyTime(13,20,15);
        t1.display();
        t1.addSecond(121);
        t1.display();
    }
}
class MyTime{
    private int hour;
    private int minute;
    private int second;

    public void addSecond(int sec){
        int oldSec = this.getSecond();
        int newSec = oldSec +sec;
        if(newSec < 60){
            this.setSecond(newSec);
        }else if(newSec == 60){
            this.addMinute(1);
            this.setSecond(0);
        }else{
            this.addMinute(newSec / 60);
            this.setSecond(newSec % 60);
        }
    }
    public void addMinute(int min) {
        this.setMinute(this.getMinute() + min);
    }//由于下列方法类似,不再赘述解决数学问题
     //还可以采用秒处理的方法对此类题进行处理   
    public void addHour(int hou){

    }
    public void subSecond(int sec){

    }
    public void subMinute(int min){

    }
    public void subHour(int hou){

    }

    public void display(){
        System.out.println(this.getHour() + "时"  + this.getMinute() + "分" + this.getSecond() + "秒");
    }

    public void setHour(int hour) {
        this.hour = hour;
    }

    public void setMinute(int minute) {
        this.minute = minute;
    }

    public void setSecond(int second) {
        this.second = second;
    }

    public int getHour() {
        return hour;
    }

    public int getMinute() {
        return minute;
    }

    public int getSecond() {
        return second;
    }

    public MyTime() {
    }

    public MyTime(int hour, int minute, int second) {
        this.hour = hour;
        this.minute = minute;
        this.second = second;
    }
}

23、包装类

23.1 引入包装类的目的

假设有一个方法的参数是Object类型的,现在需要传入一个整数,如何解决?

这时候把100这个 数字经过构造方法包装成对象

MyInt myint = new MyInt(100);

上面MyInt就是一个自定义的包装类

23.2 关于包装类

Java中除了8种基本数据类型之后又有8种包装类型,这八种包装类型属于引用数据类型

基本数据类型

基本数据类型									包装类型
byte									java.lang.Byte(父类NUmber)
short									java.lang.Shrot(父类NUmber)
int										java.lang.Integer(父类NUmber)	
long									java.lang.Long(父类NUmber)
float								    java.lang.Float(父类NUmber)
double									java.lang.Double(父类NUmber)		
boolean									java.lang.Boolean(父类Object)			
char									java.lang.Character(父类Object)			

23.3 关于部分包装类的父类Number

Number是一个抽象类,无法实例化对象

Number中有以下方法:(负责拆箱)

byte byteValue()	以byte形式返回指定的数值
abstract double doubleValue()	以double的形式返回指定数值
abstract float floatValue()		以float的形式返回指定的值
abstract int intValue()			以int的形式返回指定的值
abstract long longValue()		以long的形式返回指定的值
short shortValue()				以short的形式返回指定的值	

这些方法其实所有子类中都有

23.4 Integer类的构造方法

将整形转换成Integer包装类型 Integer(int)

将String类型转换成Integer类型 Integer(String)

23.5 自动装箱/拆箱

自动装箱 int --> Integer Integer x = 100;

自动拆箱 Integr --> int int y = x;

//z保存的是内存地址
Integer z = 100;//等同于 Integer z = new Integer(100);
System.out.println(z + 1);//这里z自动拆箱

注意:java中为了提高程序的执行效率,将【-128到127】之间所有的包装对象提前创建好,放到一个方法区的"整数型常量池"当中了,目的是只要在这个区间的数据都不需要再new了,直接从整数型常量池当中取出来

Integer a =128;//Intteger a = new Integer(128);
Integer b =128;//Intteger b = new Integer(128);
System.out.println(a == b);//false

Integer x =127;
Integer y =127;//x,y当中保存的内存地址是一样的
System.out.println(x == y);//true

在这里插入图片描述

23.6 数字格式化异常

之前所学的经典异常

1)空指针异常 NullPointerException

2)类型转换异常 ClassCastException

3)数组下标越界异常 ArrayIndexOutOgBoundsException

4)数字格式化异常 NumberForematException

Integer a = new Integer("中文");//编译没问题,运行时出现数字格式化异常

23.7 Integer中常用方法

23.7.1 Integer的String转int方法

parseInt()方法

static int parseInt(String s)

用途:网页上文本框输入的100实际上是字符串"100",而后台数据库要求存储100数字,这时候需要将"100"转换成100

唯一静态方法,传String,返回int

int retvalue = Integer.parseInt("123");
double retvalue = Double.parseInt("3.14");

23.7.2 *十进制转二进制

Integer.toBinaryString(3);//11

23.7.3 *十进制转十六进制

Integer.toHexString(16)//10

23.7.4 *十进制转八进制

Integer.toOctalString(8)//10

23.7.5 valueOf方法

静态的 int——>Integer

static Integer valueOf(int i)

静态的 String——>Integer

static Integer valueOf(String i)

23.8 String、int、Integer三者的互相转换

在这里插入图片描述

//String ——> int
int i = Integer.parseInt("100");//i是100数字
System.out.println(i+1);//101

//int ——> String
String s = i + "";//"100"字符串
System.out.println(s+1);//"1001"

//int ——> Ingeter
//自动装箱
Integer x = 1000;
    
//Integer ——> int
//自动拆箱
int y = x;

//String ——> Integer
Integer k = Integer.valueOf("123");

//Integer ——> String
String e = String.valueOf(k);

24、对时间的处理

24.1 获取系统当前时间(精确到毫秒的系统当前时间)

直接调用无参数构造方法就行

Date nowTime = new Date( )
System.out.println(nowTimw);

java.utill.Date类的toString()方法已经被重写了,输出的应该不是一个对象的内存地址,应该是一个日期字符串

24.2 日期格式化

1)将日期类型Date,按照指定的格式进行转换:Date——>String

SimpleDateFormat是java.text包下的,专门负责日期转换的

yyyy 年(年是4位)
MM	月(月是2位)
dd	日
HH	时
mm	分
ss	秒
SSS	毫秒(毫秒3位,最高999,1000毫秒代表1秒)

注意:在日期格式化中,除了y M d H m s S这些字符不能随便写之外,剩下的符合格式自己随意组织

Date nowTime = new Date( )
System.out.println(nowTimw);
SimpleDateFormat sdf = new SimpleDateFormat("yyy-MM-dd HH:mm:ss SSS");//日期格式化
String nowTimeStr = sdf.format(nowTime);//Date类型转换成String类型
System.out.println(nowTimwStr);

2)将String类型转换成日期类型Date:String——>Date

Date nowTime = new Date( )
String time = "2008-08-08 08:08:08 888";
SimpleDateFormat sdf2 = new SimpleDateFormat("yyy-MM-dd HH:mm:ss SSS");//日期格式化
Date dataTime = sdf2.parse(time);//String类型转换成Date类型
System.out.println(dataTime);

注意:字符串的日期格式和SimpleDateFormat对象的日期格式要相同

3)获取自1970-1-1 00:00:00 000当当前系统时间的总毫秒数

long nowTimeMillis = System.currentTimeMills();

System.out.println(nowTimeMillis);

解决的需求:可以计算一个方法调用的方法耗用的时间

4)Date(long date)【距离1970-1-1 08:00:00 000多少毫秒的日期】

Date time = new Date(1)//参数是一个毫秒
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS");
System.out.println("sdf.format(time)");

25、System类

System.out 【out是System类的属性】

System.out.println( ) 【println( )方法不是System类的方法,是PrintStream类的方法】

System.gc( ) 【建议启动垃圾回收器】

System.currentTimeMillis() 【获取自1970年一月一日到系统当前时间的总毫秒数】

System.exit(0) 【退出JVM】

26、*数字格式化

1)java.text.DecimalFormat专门负责数字格式化的【转成字符串】

format()方法

DecimalFormat df = new DecimalFormat(“数字格式”);

2)数字格式有哪些?

#	代表任意数字
,	代表千分位
.	代表小数点
0	代表不够时补0
DecimalFormat df = new DecimalFormat("###,###.###");
String s = df.format(1234.56);
System.out.println(s);//1,234.56

DecimalFormat df2 = new DecimalFormat("###,###.0000");//表示保留四位小数,不够时补0
String s2 = df2.format(1234.56);
System.out.println(s2);//1,234。5600

27、高精度BigDecimal

1)java.math.BigDecimal

2)属于一个大数据,精度极高,不属于基本数据类型,属于java对象(引用数据类型),用在财务软件当中(double不够用)

BigDecimal v1 = new BigDecimal(100);
BigDecimal v2 = new BigDecimal(100);
BigDecimal v3 = v1.add(v2);//调用方法求和,不能用v1 + v2;
System.out.println(s3);//300

28、随机数

随机产生int取值范围内的随机数

28.1 new Random()

导包: import java.util.Random

这种需要借助java.util.Random类来产生一个随机数发生器,也是最常用的一种,构造函数有两个,Random()和Random(long seed)。第一个就是以当前时间为默认种子,第二个是以指定的种子值进行。产生之后,借助不同的语句产生不同类型的数。

其中,种子就是产生随机数的第一次使用值,机制是通过一个函数,将这个种子的值转化为随机数空间中的某一个点上,并且产生的随机数均匀的散布在空间中。以后产生的随机数都与前一个随机数有关。这里以代码为例。

//创建随机数对象
Random random = new Random();
//随机产生一个int类型取值范围内的数字
int num1 = random.nextInt();
System.out.println(num1);
//产生【0-100】之间的随机数。不能产生101
int num2 = random.nextInt(101);//nextInt翻译为:下一个int类型的数据是101,表示只能取到100,不包括101
System.out.println(num2);

28.2 Math.random()可以设置上下限

这种方法返回的数值是[0.0,1.0)的double型数值,由于double类数的精度很高,可以在一定程度下看做随机数,借助(int)来进行类型转换就可以得到整数随机数了,代码如下。

public static void main(String[] args)
{
    int max=100,min=1;
    int ran2 = (int) (Math.random()*(max-min)+min);
    System.out.println(ran2);//返回值的范围【1,100】;
}

28.3 *currentTimeMillis()

public static void main(String[] args)
{
    int max=100,min=1;
    long randomNum = System.currentTimeMillis();
    int ran3 = (int) (randomNum%(max-min)+min);
    System.out.println(ran3);
}

这种方法返回从1970年1月1日0时0分0秒)到现在的一个long型的毫秒数,取模之后即可得到所需范围内的随机数。

29、枚举类型的使用

1)枚举:一枚一枚可以列举出来的,才建议使用枚举类型

枚举编译之后也是生成class文件

枚举是一种引用数据类型

枚举中的每一个值可以看作是常量

enum Result//枚举{
	//SUCCESS 是枚举Result类型中的一个值
	//FAIL是枚举Result类型的一个值
	SUCCESS,FAIL//枚举值1,枚举值2
}

2)结果只有两种情况的,建议使用布尔类型,结果超过两种的建议使用枚举类型,例如:颜色、天气、星期

3)高版本JDk swith支持int、String、枚举类型、【byte、short、char】也可以,因为存在自动类型转换

switch(Season.AUTUMN){
	case SPRING:	;break;//不能加Season.
	case SUMMER:	;break;
	case AUTUMN:	;break;
	case WINTER:	;break;
}
enum Season{
	SPRING,SUMMER,AUTUMN,WINTER
}

30、异常

1)什么是异常,java提供异常处理机制有什么用?

以下程序执行过程中发生了不正常的现象,而这种不正常的情况称为异常

java把异常信息打印到控制台,供程序员参考,程序员看到异常信息之后可以对其进行修改,使程序更加健壮

public static int divide(int a,int b){
	try{
		int c = a / b;
        //程序执行到此处表示以上代码没有发生异常,表示执行成功
		return 1;
	}catch(Exception e){
		//程序执行到此处表示以上程序出现了异常
		//表示执行失败
		return 0;
	}
}

2)异常信息如何产生的?

JVM虚拟机在处理到异常的时候会new一个异常对象,并且JVM将new的异常对象抛出,打印输出到控制台了;

30.1 基本概念

编译时异常和运行时异常都是发生在运行阶段编译阶段异常不会发生

编译时异常必须在编译(编写)阶段预先处理,如果不处理编译器报错;

所有异常都是在运行阶段发生的,因为只有程序运行阶段才可以new对象。异常的发生就是new异常对象

30.2 编译时异常和运行时异常

编译时异常(受检异常、受控异常)发生概率较高,需要在运行之前对其进行预处理;

运行时异常(未受检异常、非受控异常)发生概率较低,运行之前不需要进行预处理;

30.3 对异常的处理

1)在方法声明的位置上,使用throws关键字;【抛给上一级,谁调用我,我就抛给谁;抛给上一级同样有两种方式】

java中异常发生之后如果一直上抛,最终抛给了main方法,main方法继续向上抛,抛给了调用者JVM,JVM终止程序的执行

2)使用try…cathch语句进行异常的捕捉;【这件事发生了谁也不知道,因为我给抓住了】

public class Sttt{
    public static void main(String[] args) {
        System.out.println(100/0);
//程序执行到此发生ArithmeticException异常,底层new了一个ArithmeticException异常对象,然后抛给了main方法,main方法最后无法处理,将异常抛给了JVM,JVM最终终止了程序的执行
        System.out.println("helloworld");
    }
}
//ArithmeticException 继承 RuntimeException,属于运行时异常,在编写程序时不需要对这种异常进行预先处理
public class Sttt{
    public static void main(String[] args)throws ClassNotFoundException//处理方式1 {
		doSome();//因为doSome方法()的声明位置上有 throws ClassNotFoundException 所以在调用的时候要对这种异常进行预先的处理,不处理,编译器会报错
    
    	//Alt + 回车 可以生成
    	
    	try {
            doSome();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }//处理方式2
    }
}
public static void doSome() throws ClassNotFoundException{
//ClassNotFoundException类没找到异常,父类是Exception,所以属于编译时异常
}

3)在抛出异常时,可以抛出该异常的父对象

throws后面可以写多个异常,并且用逗号隔开;

一般不建议在main方法上使用throws,因为这个异常如果真的发生了,一定会抛给JVM,JVM只能终止

异常处理机制的作用就是提高程序的健壮性,保证程序出现了异常也能执行,所以main方法中的异常建议是使用try…catch进行捕捉。main不要继续上抛了

注意:只要异常没有捕捉,采用上报的方式,此方法的后续代码不会执行,另外需要注意:try语句块的某一行出现异常,改行后面的代码不会执行,try catch后续的代码仍然执行

30.4 深入try…catch异常

30.4.1 try…catch的格式

try{
    //try尝试
	m1();
}catch(FileNotFoudException e){
	//catch是捕捉异常之后走的分支
    System.out.println("文件不存在,可能路径写错了,也可能该文件被删除了");
}

30.4.2 关于try…catch

1、catch后面的小括号中的类型可以是具体的异常类型,也可以是该异常类型的父类型

2、catch可以写多个,便于程序的调试,catch写多个的时候从上到下,必须遵守从小到大

30.4.3 JDK新特性

try{
	
}catch(FileNotFoundException|ArithmeticException|NullPointerException e){

}

30.5 上报和捕捉如何选择

如果希望调用者来处理,则选择throws上报

30.6 getMessage()方法和printStackTrace()方法

public class Sttt{
    public static void main(String[] args) {
        //这里为了测试两个方法,而new的异常对象,但是没有吧异常对象抛出,JVM认为是一个普通的java对象
        NullPointerException e =new NullPointerException("空指针异常!");
        //获取异常简单描述信息:这个信息实际上就是构造方法中的String参数
        String msg = e.getMessage();
        System.out.println(msg);
        e.printStackTrace();//打印异常信息,java后台打印异常堆栈信息的时候采用了异步线程的方式打印的
    }
}

30.7 finally子句

1)在finally子句中的代码是最后执行的,并且是一定会执行的,即使try语句块的代码出现了异常,

2)finally子句必须和try一起出现,不能单独编写;

3)finally语句通常使用在完成资源的释放/关闭,因为finally语句块中的代码比较有保障,即使try语句块中的代码出现异常,finally中的代码也会正常进行

4)try语句块即使有return,那么finally也会执行,只有当System.exit(0)退出JVM时,才不会执行finally

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;


public class Sttt{
    public static void main(String[] args) {
        FileInputStream fis = null;//声明位置放到try外面,这样才能在finally中使用
        try{
            FileInputStream fis = new FileInputStream("D:\java\javase");
                    //开始读文件
                    String s = null;
                    //这里空指针异常
                    s.toString();
                    //流用完需要关闭,因为流是占用资源的
                    //即使上面程序出现异常,流也必须关系
                    //放在这里有可能关不了
        }catch (FileNotFoundException e){
            e.printStackTrace();
        }catch (IOException e){
            e.printStackTrace();
        }catch (NullPointerException e){
            e.printStackTrace();
        }finally {
            //流的关闭放到这里比较保险
            //finally中的代码是一定会执行的
            //即使try中出现了异常
            if(fis != null)//避免空指针异常
                try{
                    //close()方法有异常,采用捕捉的方式
                    fis.close();
                } catch(IOException e){
                    e.printStackTrace();
                }
        }
    }
}

5)面试题

java的语法规则:

方法体中的代码必须遵循自上而下顺序依次逐行执行(亘古不变的语法)

return语句一旦执行,整个方法必须结束

public class Sttt{
    public static void main(String[] args) {

        System.out.println(m());//结果是100
    }
    public static int m(){
        int i= 100;
        try{
            //这行代码出现在 int i = 100;的下面,所以最终结果必须是返回100
            //return 语句还必须保证是最后执行的,一旦执行,整个方法结束
            return i;
 //这里可以理解为自上而下i已经传入了return中但是还没有执行,所以后面的finally无论在return前怎么改变i的值,return i都不会改变
        }finally{
            i++;
        }
    }
}

反编译的代码

public static int m{
	int i = 100;
	int j = i;
	i++;
	return j;
}

30.8 final、finally和finalize的区别

final

final是一个关键字。表示最终的、不可变的

final int i = 100;

finally

finally也是一个关键字。和try连用,使用在异常处理机制当中

finally语句块中的代码一定会执行的

try{

}finally{
	
}

finalize()

finalize()是Object类的一个方法,作为方法名出现,所以finalize是标识符

finalize()方法是JVM的GC垃圾回收器负责调用

30.9 自定义异常

30.9.1 自定义异常的步骤

第一步:编写一个类继承Exception或者RubtimeException

第二步:写两个构造方法,一个无参构造方法和一个有参构造方法

注意:throw在手动抛异常的时候使用throws表示上报异常信息给调用者

public class Sttt{
    public static void main(String[] args) {
        //new了一个异常对象(没有手动抛出)
		MyException e = new MyException("用户名不能为空");
        //打印异常信息
         e.printStackTrace();
        //获取异常简单描述信息
        String msg = e.getMessage();
        System.out.println(msg);
    }
}

public class MyException extends Exception{
	public MyException(){
		
	}
	public MyException(String s){
		super(s);
	}
}

注册登录页面

public class Sttt{
    public static void main(String[] args) {
        UserService userService = new UserService();
        try {
            userService.register(null,"123");
        }catch (IllegalNameException e){
            System.out.println(e.getMessage());
        }
    }
}
class IllegalNameException extends Exception{
    public IllegalNameException() {

    }
    public IllegalNameException(String s) {
        super(s);
    }
}
class UserService {

    public void register(String username,String password) throws IllegalNameException {
        if(username == null||username.length()<6||username.length()>14){
            throw new IllegalNameException("用户名不合法!");
        }
        System.out.println("注册成功");
    }
}

30.9.2 栈内存程序的改进

public class Text {
    public static void main(String[] args) {
        //创建一个栈对象,初始化容量是10个
        Stack s = new Stack();
        s.push("12345ty");
        s.push(new Object());
        s.push(new Object());
        s.push(new Object());
        s.push(new Object());
        s.pop();
        s.pop();
        s.pop();
        s.pop();
        s.pop();
        s.pop();
        //可以使用for循环进行压栈和弹栈
    }
}
class Stack{
    //存储任何引用类型数据的数组
    private Object[] elements;
    //有参构造方法
    public Stack(Object[] elements) {
        this.elements = elements;
    }
    //无参构造方法
    public Stack() {
        //一维数组动态初始化
        //默认初始化容量为10
        this.elements = new Object[10];
    }
    //栈帧(永远指向栈顶元素)
    private int index=-1;
//压栈方法
public void push(Object obj) throws MystackQperationException{
    
    
                      //重点!!!!!!!!!!!!!
    if(this.index >= this.elements.length-1){
        throw new MystackQperationException("栈内存已满,压栈失败");
        //不要进行try...catch,自己new自己抓的操作,必须抛给调用者
    }//这里进行了改进
                      //重点!!!!!!!!!!!!!
    
    
    index++;
    elements[index] = obj;
    System.out.println(obj + "元素,压栈成功,栈帧指向" + index);
}

//弹栈方法
public void pop() throws MystackQperationException{
    
    
                    //重点!!!!!!!!!!!!!
    if(this.index <= -1) {
        //System.out.println("栈内存已空,弹栈栈失败");
        throw new MystackQperationException("栈内存已空,弹栈栈失败");  
    }
                    //重点!!!!!!!!!!!!!
    
    
    else
        System.out.println(elements[index] + "元素,弹栈成功,栈帧指向" + --index);
}
//自定义栈操作异常
public class MystackQperationException{
    public MystackQperationException{
        
    }
    public MystackQperationException(String s){
        super(s);
    }
}
//static实例变量的get方法
public Object[] getElements() {
    return elements;
}
//static实例变量的set方法
public void setElements(Object[] elements) {
    this.elements = elements;
}
//实例变量栈帧的get方法
public int getIndex() {
    return index;
}
//实例变量栈帧的set方法
public void setIndex(int index) {
    this.index = index;
}
}

30.10 子类重写的方法抛出编译异常只能更少/小不能更多

class Animal{
	public void doSome(){
	
	}
	public void doOther() throws Exception{
	
	}
}
class Cat extends Animal{
	public void doSome() throws Exception{
		//编译报错
	}
    public void doOther() throws Exception{
		//编译正常
	}
    public void doOther(){
		//编译正常
	}
    public void doOther() throws NullPointerException{
		//编译正常
	}
    public void doSome() throws RuntimeException{
		//运行编译子类可以正常抛出更多,而编译异常不行
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

胖虎不秃头

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值