五、面相对象
1.面向对象
面向过程和面向对象都是解决问题的一种思想模式。
面向过程:指的就是按照一定的步骤,逐一执行,将问题进行解决。
相当于是一个 执行者 角色。
面向对象:指的就是找对象(对象内部应该有所需要的那些功能)解决问题。
相当于是一个 指挥者 角色。
找对象,创建对象,调用其功能(方法)
封装对象 创建对象 调用其功能(方法)
注意:在java中,什么都是对象,具体的,抽象的、有生命的、无生命的都是对象
千万不要局限于指的是人。
比如: 花、草、天气、电脑、人....
面向对象特征:
封装 继承 多态
2.类和对象之间的关系
引用类型: 数组 类 接口 枚举
类: 一种数据类型
使用class来定义的都是该类型对应的数据
一组属性和行为的集合,即一组变量和方法的集合。
属性: 数据,变量
行为: 功能,方法
是用来描述一类事物的,将这类事物的共性内容进行抽取,封装到类中。
比如: 描述人这类事物
属性: 人这类事物的共性数据描述 ,如:身高、体重、姓名...
行为: 人这类事物的共性能做的事情,如:吃饭、睡觉、打游戏...
对象:指的是一类的真实存在的个体(实例)。
形象上理解: 类相当于是模板,对象是一个真实个体
如:类:class Phone{} 对象: new Phone()
定义类格式:
修饰符 class 类名{
属性;... 变量
行为;... 方法,将修饰符static去掉(因为加上static 就是静态方法,静态方法是一种特殊的方法,又称类方法,是在加载类的时候直接进入内存,不需要实例对象就可以调用,类名.方法名 就可以调用)
}
创建对象:
类名 对象名 = new 类名();
访问类中的成员变量或成员方法:
对象名.成员名
3.对象内存的理解
创建一个对象:
Person p = new Person();
对象实例化过程:
1.加载Person.class文件到方法区
2.在栈中创建p引用变量,是Person类型的
3.在堆中开辟空间,并分配地址值
4.在堆中存储默认值
5.将地址值赋值给p变量,p引用/指向了该空间
注意:class只加载一次。
Person p1 = p;
将p的值赋值给p1,说明p和p1指向同一个对象。
4.成员变量和局部变量的区别
\1. 书写位置
成员变量: 类中,方法外
局部变量: 方法中,方法上,语句中
\2. 内存位置
成员变量: 在堆中
局部变量: 在栈中
\3. 作用域
成员变量:整个类中都可以使用
局部变量:在当前定义的所属的大括号中
\4. 默认值
成员变量:有默认值,取决于数据类型
局部变量:没有默认值,需要赋值后才能使用
\5. 生命周期
成员变量:创建对象存在,对象销毁消失。
销毁就是被gc回收。没有引用变量指向的对象就是垃圾,等待被回收。
局部变量:随着方法进栈存在,随着方法出栈消失。
5.匿名对象
1.字面理解:就是没有名字的对象。
2.实际含义:创建的对象,没有引用变量来指向。
例如: new Person();
3.访问属性:
没有意义,访问完称为垃圾,等到被gc回收。
4.访问方法:
有点意义,能调用一次方法,仅仅是一次。
测试某个方法是否逻辑正确,可以创建匿名对象去调用此方法。
5.作为参数传递:
该对象后期不再进行使用,就是用匿名方式传递,对象成为垃圾最终会被回收。
如果使用有名方式传递,该对象不会是垃圾。
6.作为方法的返回值:
如果返回的是匿名对象,如果有变量接接这个结果,该对象不是垃圾。
如果是没有变量来接受,该对象方法执行完就成为垃圾。
6.封装
面向对象的特征,强调的是对象的封装。
与对象有关的是:属性和行为。
概念:将对象的属性或行为隐藏起来,对外提供公共的给访问方式。
关键字:
private:
权限修饰符,私有的意思,被修饰的内容,只能在当前类中使用。
修饰的是类中的成员。
成员:变量、方法、类(内部类)
public:
权限修饰符,权限最大,是公共的意思。
属性私有化:对外提供两个方法,一个是用于给属性进行赋值的,一个是用于给属性获取。
创建的方法的名字是自定义的,主要是合法的标识符就可以的。但是,对于这样的一组方法有一个规范,建议大家都遵守,方法名的格式:
set属性名和get属性名
例如:setName 赋值 getName获取
问题:
成员位置和局部位置变量名重名,导致赋值不成功。
java有一个原则,叫做就近原则,意思就是内部有直接用,不出去找如果没有才出去找。
解决:
this:
是一个隐藏的变量,任何一个类中都有。
代表的是当前类对象的引用,谁调用this所在的方法,那么它就代表谁。
结论:
类中的成员(变量和方法),想要访问,必须通过 对象名.成员名 来访问。
直接调用访问,是因为前边省略了 this.
解决重名问题必须写,其他情况可以省略。
注意:
不是说属性和行为私有了就是封装,私有只是封装的一种体现。
好处:
1.提高代码的安全性。 2.提高代码的维护性
7.构造方法
this:
1.解决成员位置和局部位置变量名重名问题。
2.调用重载的构造方法
名称:构造方法,也叫做构造器,构造函数
“
普通
修饰符 返回值类型 方法名(参数列表){
public int getmax (int a ,int b){
return 返回值;
return a >b ? a: b ;
}
”
构造方法格式:
//构造方法
修饰符 方法名(参数列表)
public Persons(){
super();
System.out.println("我执行了~~~");
}
public Persons(int age){
this();
this.age = age;
}
public Persons(String name , int age){ //name = zhangsan age = 20
this(age); //调用重载的构造方法
this.name = name;
this.age = 40;
}
修饰符: public private 默认
方法名: 类名,包括大小写一致
特点:
1.创建对象时,根据new后边的实参列表,找到对应的构造方法去调用执行
2.支持方法重载
3.构造方法中没有 return 返回值; 语句,想要有return关键字,只能是 return;
作用:
主要是用于给对象的属性进行初始化。
说明:注意构造方法中不一定非要是属性的赋值语句,也可以有循环、调用方法等。
构造方法也是方法,只不过比较特殊而已,因此也是可以对应的逻辑代码语句的。
对象只能创建一次,创建的时候会自动调用构造方法来完成属性的赋值操作,构造方法对于该对象来说,只能调用一次。
问题1:
既然构造方法可以给属性进行赋值,还需要set方法?
依然需要,因为构造方法仅仅是对象创建是执行,set方法是在对象创建后可以多次调用执行,对属性值进行改变。
问题2:
构造方法能调用其他普通方法?
是可以的,但是这种调用比较少。
问题3:
普通方法能调用构造方法吗?
不能,构造方法只能在创建对象的时候完成初始化。
问题4:
Person p = new Person(“张三”,30);
对象的实例化过程:
1.加载Person.class文件到方法区
2.在栈中创建p引用变量,是Person类型的
3.在堆中开辟空间,并分配地址值
4.在堆中存储默认值
5.属性如果有显示值,那么进行显示初始化,如果没有跳过此步
6.执行构造方法初始化,将张三和30赋值给对象的属性
7.将地址值赋值给p变量,p引用/指向了该空间
问题5:
重载构造方法的调用。
//构造方法
public Persons(){
// this("",18); 至少有一个不能写this,是给super留位置,就算是不写super,默认第一行也是有的
System.out.println("我执行了~~~");
}
public Persons(int age){
this();
this.age = age;
}
public Persons(String name , int age){ //name = zhangsan age = 20
this(age); //调用重载的构造方法
this.name = name;
this.age = 40;
}
需要使用 this(实参); 这个语句来实现。
要求:这个语句必须放在构造方法的第一行。目的就是为了让该语句优先执行。
注意:重载形式的构造方法的第一行,至少有一个构造方法不能写 this(实参); 语句,不然就是死循环。
问题6:
之前创建对象时,类中没有定义过构造方法,对象也创建成功了?
类中没定义是因为系统提供了一个无参数,无方法体的构造方法 public 类名(){}。
但是,在类中定义过了构造方法了,那么系统不再提供,必须以编写的构造方法的格式来创建对象。
8.JavaBean类
指的就是一个实体类(对象类),是一种规范。
类中成员:
1.属性必须私有化
2.必须有set和get方法
3.必须有无参数构造方法,显示
4.有参构造(可选)
5.用于返回属性信息方法(可选)
类要求:必须是public修饰的类。
package com.ujiuye.day08;
//描述某个事物类
//该类要符合JavaBean的规范
public class Students {
//1.属性私有化
private String name;
private int age;
//2.无参数构造方法
public Students(){}
//4.有参构造方法 可选
public Students(String name,int age){
this.name = name;
this.age = age;
}
//3.set和get方法
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
//5.返回属性信息的方法 可选
public String getInfo(){
return name +"...."+age;
}
}
9.继承
static关键字
静态的意思,是一个成员修饰符。可以修饰类中的成员变量、成员方法、成员内部类。静态过的变量和方法在创建对象之前就已经在内存中,直接进栈,不需要对象
没有静态前:描述一个类型后,创建该类型对象,发现每个对象中都有一个共同的数据,这样导致内存空间浪费,如果要对该值进行修改,需要修改多次,维护成本增高。
说明:这样做也是可以的,不做优化没问题。
静态后:在内存中,只是开辟一块空间,存储共同数据,这个数据可以被该类型的所有对象所共享,如果值要改变,仅仅修改一次即可。降低内存空间浪费和维护的成本。
静态变量的方法: 在变量前面加上 static 修饰符即可
static修饰成员变量特点:
1.在类加载时,静态变量存储在方法区的静态区域,并存储默认值。
2.被该类型的所有对象所共享
3.优先于对象存储在内存中
4.生命周期长,随着类的加载而加载,随着类的消失而消失
5.被static修饰的变量
静态变量 、类变量 ,与对象无关
访问方式 : 类名.静态变量名 推荐
对象名.静态变量名
注意:千万不能为了调用简单而使用static就是变量,当所有对象共享同一个资源数据时,使用static修饰。
成员变量和静态变量区别:
\1. 内存位置
成员变量:存储在堆中
静态变量:存储在方法区中的静态区域
\2. 访问方式
成员变量: 对象名.成员名
静态变量: 对象名.成员名 类名.成员名 推荐
\3. 生命周期
成员变量:随着对象创建而存在,随着对象被gc回收而消失
静态变量:随着类的加载而加载,随着类的消失而消失
\4. 称呼上:
成员变量: 对象变量 实例变量
静态变量: 类变量
访问局限:
1.静态方法中可以访问静态成员(变量和方法)
2.静态方法中不能访问非静态成员
3.非静态方法中既可以访问非静态也可以访问静态
总结:静态方法中不能出现与对象直接有关的内容,因为静态方法在加载类的时候就已经进入内存,静态方法不需要实例对象就可以直接调用,通过 类名.静态方法名。
在静态方法中不能出现this和super关键字:因为this和super关键字在实例中只能通过对象来调用,静态方法不出现与对象有关的内容,所以不能出现this和super关键字。
工具类:
类中没有所需要维护的数据时,仅仅只有方法。
步骤:
1.定义类,类名通常是见名知意
2.私有化构造方法:因为别人写好的功能,不希望有人改动。
3.方法都是静态的,方便直 接类名.方法名 拿来使用,不用创建实例对象。
继承
模拟现实生活中的父和子的关系,在java中也有类似的关系,指的就是类和类间也有继承关系。当描述Student 和 Teacher两个不同的事物时,发现有共性的内容(属性和行为),将这些内容进行提取,定义到Person类中,让Student和Teacher与Person产生关系,Student和Teacher可以直接使用Person类中的内容,这种关系就是---继承。
定义:
从一个类中派生出(衍生出)其他类的过程。
原来的类称为: 父类、超类、基类
派生出的类称为: 子类
关键字:
extends 继承
class A extends B{}
好处:
1.提高了代码的复用性
2.面向对象的第三特征--多态
弊端:
增强了耦合度。
子类继承父类后,相当于将父类中的成员继承,可以直接使用。
子类只需要定义自己特有的成员属性和成员方法即可,也可以不定义。
注意:
1.构造方法不继承 因为构造方法名要求与类名一致,如果继承则冲突。
2.私有成员不被继承 (官方文档显示)
实际在子类中依然有父类中的私有成员,只不过是子类不能直接对其进行操作,只能通过继承的get和set方法间接使用。
在java中,一个类只能有一个父类,这是java的单继承特点。
一个父类可以有多个子类。这些子类是平级关系,即兄弟关系。
注意:
不能为了提高代码的复用性而乱使用继承,必须是有 is--->a关系,就是一种类似于父子间继承的关系。
继承中成员变量的特点:
1.现在子类局部范围找
2.子类成员方法范围找
3.父类的成员方法找
4.父类的父类找....... 知道找到object ,如果都找不到就会编译报错
this:
代表的是当前类对象的引用,可以访问子类中成员也可以访问父类中成员,就近原则,子类中有就用子类的,子类没有就用父类的
super:
它的用法和this基本上是一致的,都可以访问成员变量和成员方法,只不过super访问的是父类中的成员,因为super代表的是父类型引用。不管子类有没有都是只用父类的。
问题:创建子类对象时,父类对象创建了吗?
没有创建。只不过是子类中持有一个父类型引用,即super,可以去访问父类中的成员。
方法重写
子类和父类中,有相同的方法定义,方法名相同,方法的主体不同,创建子类对象调用该方法,运行的是子类中的内容,这种现象叫做方法的重写/覆盖。
overload:重载
同一个类中,方法名相同,参数列表不同,与返回值类型无关
overried:重写
在子父类中,子类重写父类中的方法
为什么要重写?
继承的方法的方法主体不满足于子类的需求。
重写方法要求:
1.私有方法不重写。即使在子类中写了该方法,貌似重写,实际是重新定义。
通过@Override注解来验证,这个注解写在重写方法的上边。
2.重写方法的权限修饰符要大于等于父类方法的
权限修饰符 public > protect > default (默认) > private
3.重写方法的返回值类型小于等于父类方法的返回值类型
为了保证重写正确:
修饰符 返回值类型 方法名 参数列表 都与父类的一致。
继承中的构造方法
创建子类对象时,发现父类的构造方法也执行了(无参数的),是因为子类构造方法的第一行有一条隐藏的 super();语句,这条语句的作用就是调用父类的无参数构造方法。
构造方法: 用于给属性进行初始化。
为什么要执行父类构造方法?目的就是为了让父类的属性先进行初始化。在子类属性执行初始化之前,父类属性先初始化,子类所有的构造方法调用之前都会调用父类的无参构造方法,每一个子类构造方法之前都会有一个super();
注意:父类的构造方法一定要执行,而且一定是在子类构造方法之前执行的。 父类中没有无参数构造方法,子类构造方法的第一行必须显示写出super(参数)语句。this() 和 super()都需要放在构造方法的第一行,因此它俩不能同时存在。
//第一种:
public SubClass(){ // 自动调用父类的无参数构造器
System.out.println("SubClass");
}
public SubClass(int n){
super(300); // 调用父类中带有参数的构造器
System.out.println("SubClass(int n):"+n);
this.n = n;
}
//第二种
public SubClass2(){
super(300); // 调用父类中带有参数的构造器
System.out.println("SubClass2");
}
public SubClass2(int n){ // 自动调用父类的无参数构造器
System.out.println("SubClass2(int n):"+n);
this.n = n;
}
10.知识总结
\1. 面向过程:当需要实现一个功能的时候,每一个过程中的详细步骤和细节都要亲力亲为。
\2. 面向对象:当需要实现一个功能的时候,不关心详细的步骤细节,而是找人帮我做事儿。把需求不自己亲自解决,而是交给对象解决。对象是我们提前设计好的能有一定功能的代码,当我们需要的时候直接调用对象实现其功能。
比如:洗衣服的面向过程的理解就是,每次洗衣服都拿盆放水放洗衣液自己
洗完拧干晾衣服,每次洗衣服都是这个重复的工作。面向对象的思想就是,我把这些重复的工作设计到一个全自动洗衣机里,
或者买一个全自动洗衣机,我每次洗衣服的时候只需要把衣服放进洗衣机打开开关就行。自己设计洗衣机就是自己设计代
码块,买洗衣机就是拿别人设计好的-可以实现该功能的代码,我们直接复制过来。
\3. 类和对象的关系:
a) 类是抽象的,通常不能直接使用。好像是一张手机设计图纸,存放了手机的大小形状颜色功能价格和设计了打电话发短信的方法。
b) 对象是具体的,根据类创建一个对象使用,也就是根据图纸创造一个手机,这个手机有具体的信息,颜色价格功能等。
\4. 如何定义一个类:成员变量、成员方法。
a) 成员变量:直接定义在类当中,在方法外面。
b) 成员方法:去掉static关键字,其他和此前的普通方法一样。(目前最基础阶段这么理解)
\5. 如何根据类创建对象,格式:类名称 对象名 = new 类名称();
\6. 如何使用对象:
a) 使用成员变量:对象名.成员变量名
b) 调用成员方法:对象名.成员方法名(参数)
\7. 局部变量和成员变量的不同:
a) 定义的位置不同
b) 内存的位置不同
c) 生命周期不同
d) 默认值不同
e) 作用域不同
\8. private关键字用法:直接写在成员变量前面,类外面不能直接访问,确保安全性。间接访问:编写一对儿Getter Setter方法。(特例:如果是boolean类型,getXxx必须叫做isXxx的形式。)
\9. this关键字典型用法:用来区分同名的成员变量和局部变量。在成员变量的前面写上“this.”前缀即可。
\10. 构造方法:专门用来创建对象的方法,通过new关键字创建对象就是在调用构造。
a) 构造方法不能写返回值类型,连void都不能写。
b) 构造方法的名称必须和所在的类名称完全一样,大小写也要一样。
c) 构造方法也是可以重载的。
d) 构造方法如果没有定义,默认送一个;如果定义了,那么默认的不再赠送。
\11. 如何定义一个标准的POJO类:
a) 所有的成员变量都用private修饰
b) 为每一个成员变量编写一对儿Getter Setter方法
c) 编写一个无参数的构造方法
d) 编写一个全参数的构造方法
11.代码块
使用大括号包围起来的代码区域,里边可以是多条代码
1.局部代码块
书写位置: 方法中
作用:控制局部变量的作用域
在局部块中,可以使用它所在局部位置中所定义过的变量,出了局部块,不能使用块中
定义的变量。在一个局部中,可以定义多个局部块。例如:在一方法中的代码块,只可以使用这个方法内定义过的变量,不可以使用这个方法外的常量,而且这个代码块内的定义过的变量只在这个代码块内有效。
2.构造代码块
书写位置:类中方法外
作用:用于给对象进行初始化的,优先于构造方法执行
在构造块中,编写的是所有对象共性的内容提取。在一个类中,可以出现多次的构造块,
按照从上到下的顺序,依次执行构造块,然后在执行对应的构造方法。
对象的构造方法执行过程:
1.先执行super()语句,意味着父类必须先执行
2.执行构造块,前提是有
3.执行构造方法的其他代码
4.调用几次构造方法就执行几次静态块
public class Demo1 {
//构造块
{
System.out.println("code1执行了"); //构造快1
}
public Demo1(){
super();
System.out.println("demo2 执行了");
}
public Demo1(int x){
System.out.println("demo2 执行了--"+x);
}
public static void main(String[] args) {
new Demo1(); //在调用无参构造的时候
new Demo1(10);
}
{
System.out.println("code2执行了"); //构造块2
}
}
3.静态代码块
书写位置:类中方法外,使用关键字static修饰
static{
....
}
类加载时执行,由于类仅仅加载1次,静态块只执行一次。
作用:静态变量初始化
类加载时,就需要完成一些动作,只需要执行一次的,比如:加载驱动。
在一个类中,静态块也可以出现多次,按照从上到下的顺序依次执行。
注意:静态块是在类加载完成前的最后一步去执行的。
public class Demo1 {
static int num ;
//静态块
static{
num = 100;
System.out.println("static code1111 执行了");
}
public static void main(String[] args) {
}
static{
num = 100;
System.out.println("static code1222 执行了");
}
}
构造块和静态块综合练习
public class Demo1 {
{
System.out.println("A");
}
static{
System.out.println("B");
}
public static void main(String[] args) {
new Demo1();
new Demo1();
}
public Demo1(){
System.out.println("E");
}
{
System.out.println("C");
}
static{
System.out.println("D");
}
}
// 运行结果 bdace ace
// 因为运行的时候类先加载,只要加载类就要运行静态代码块,但是只加载一次,运行构造方法之前需要运行构造块,构造方法调用几次构造块就执行几次,多个构造块的话按照从上到下的顺序。
4.同步代码块(多线程)
12.抽象类
1抽象类的特点
也是类,只不过是一个特殊一点的类。
1抽象类和抽象方法必须用abstract修饰
2抽象类中不一定有抽象方法,有抽象方法的一定是抽象类
3抽象类不能被实例化
4抽象类必须有子类,抽象类的子类要么重写这个抽象类的所有方法,要么这个子类也是一个抽象类。
abstract:
抽象的意思,是一个修饰符,可以修饰类和方法。
修饰的类:叫做抽象类
修饰的方法:叫做抽象方法。
abstract不能和private、static、final共存。
2成员:
抽象方法、成员变量、成员方法、构造方法
3.成员特点
成员变量:
可以是变量、也可以是常量
构造方法:
有构造方法,但是不能被实例化,用于子类访问父类数据的初始化
成员方法
可以有抽象方法,用于限制子类完成某些动作
也有非抽象方法,提高代码的复用性
4.抽象类的应用条件
1.该类不允许创建对象,必须有子类
2.进行多个子类内容抽取时,发现部分方法子类都将其进行了重写,父类中这些方法没必要带有方法体,因此将这些方法定义为抽象方法,抽象方法要在抽象类中。
一旦将类定义类抽象类,有一个强迫性的行为,强迫继承它的非抽象子类必须重写抽相方法。
5.final关键字
最终的、最后都意思,是一个修饰符。
修饰:类、方法、变量。
修饰类:
final class ,最终类,不能被继承。
修饰方法:
final method , 最终方法,不能被重写。
多个修饰符进行修饰时,修饰符是没有顺序的,谁在前谁在后都行。
修饰变量:
final 即可修饰成员可以修饰局部变量,修饰后叫做最终变量,不能改变。
被final修饰的变量就可以叫做常量。
常量:字面值常量 123 “hello”
符号常量
常量名: 全部大写,多个单词间使用_分隔
例如: public/private static final double MY_PI = 3.14;
final可以修饰基本类型变量 也可以修饰引用类型变量
如果修饰引用类型变量,地址值不能改,引用变量所指向的容器中的数据可以改变
-
final数据只可以被引用,不能被修改,且必须给出初始值。其优点如下
(1)增加程序的可读性,从常量名可知常量的含义 (2)增加程序的可维护性,只要在常量声明的处修改常量的值,就可以自动修改程序中所有地方使用的常量值
-
final方法的好处
(1)保持父类中某些方法的行为在继承中不发生改变 (2)提高运行效率。声明为final的方法,Java采用内联(inline)调用,即将方法代码直接插入到调用位置,这样可以降低方法调用的额外开销(入栈、跳转、执行、返回和清除栈等操作的时间和空间开销)
-
static()和private()是隐式的final()方法
13.多态
字面理解:多种状态。比如,波斯猫既是猫类,有事动物类,有时候需要调用动物类的吃饭方法,有时候需要调用猫类的抓老鼠方法,所以波斯猫有时候是猫类,有时候是动物类。
引申含义: 一个对象可以有不同的状态表示。
状态指的就是该对象的引用变量类型。
多态前提: 1.有继承和实现关系 2.有父类引用指向子类对象
多态中访问的特点: 1.成员变量: 编译执行都看左边 2.成员方法:编译看左边,执行看右边
多态表现:父类型引用指向子类的对象
多态的好处和弊端: 好处:提高了程序的扩展性,具体的表现:使用父类作为参数,将来使用的时候,使用具体的子类参与操作。 弊端:不能使用子类特有的功能。
站在对象的角度:可以使用本类型或父类型的引用变量来指向
站在引用变量类型角度: 该引用变量可以指向不同的子类对象。
多态中的转型 向上转型: 从子到父 ,父类引用指向子类对象 Animal a = new Cat(); 向下转型: 从父到子 ,父类引用强转子类对象 Cat c = (Cat) a ; f是一个定义过的父类引用
a能强转为 cat 是因为a 本来就是一只猫 假如Animal a = new Dog() 后, Cat c = (Cat) a 就会显示类型转换失败,因为a现在指向一只狗。
instanceof :比较运算符,结果是boolean类型。 格式:变量名 instanceof 类名
左边的引用变量所指向的对象是否是右边的类型
public class Animal{ //定义一个动物类
void eat(){ //定义一个方法吃东西
System.out.println("吃东西")
}
}
public class Cat extends Animal{ //定义一个猫类
void eat(){ //重写吃这个方法
System.out.println("吃鱼")
}
}
Cat boscat = new Cat;
在猫类中产生一个具体的对象波斯猫,由于猫类是动物的子类,这个波斯猫有时候是需要是动物的角色,有时候需要时猫的角色。
这个猫在不同时候有不同的状态,这就是多态。
instanceof :比较运算符,结果是boolean类型。 格式:变量名 instanceof 类名 左边的引用变量所指向的对象是否是右边的类型
public static void main(String[] args) {
Animal animal =new Cat();
printEat(new Dog());
printEat(animal);
}
public static void printEat(Animal animal){ //括号里边是父类型的参数
if (animal instanceof Cat){ //判断条件(父类型参数 instanceof 子类) 返回值是布尔类型
Cat cat = (Cat)animal;
cat.eat();
cat.mouse();
}else if (animal instanceof Dog){
Dog dog = (Dog)animal;
dog.eat();
dog.kanmen();
}else{
animal.eat();
}
}
多态的参数
//定义一个动物类
public class Animal {
void eat(){
System.out.println("吃");
}
}
//定义一个猫类,并将eat方法重写
public class Cat extends Animal {
@Override
void eat() {
System.out.println("吃鱼");
}
void mouse(){
System.out.println("抓老鼠");
}
}
//创建一个测试
public class test {
public static void main(String[] args) {
Animal animal =new Cat();
printEat(new Dog());
printEat(animal);
}
//定义一个吃的方法,使用父类作为参数,将方法体强转,这个代码就适应于多种情况
public static void printEat(Animal animal){
if (animal instanceof Cat){
Cat cat = (Cat)animal;
cat.eat();
cat.mouse();
}else if (animal instanceof Dog){
Dog dog = (Dog)animal;
dog.eat();
dog.kanmen();
}else{
animal.eat();
}
}
}
14.接口
理解: 不同事物间的共性行为的抽取。
引申含义:定义一个接口,就是在定义一个规则,这些规则指的是方法的定义。
不同事物进行抽取时,只能抽取方法的定义,不能抽取方法的主体,因此抽取的内容符合抽象方法的定义,因此接口中内容是抽象方法。方法的参数列表、方法名、返回值一旦确定,使用时必须按照定义的这些内容去使用,这些方法叫做规则。
格式:
修饰符 interface 接口名{
常量;
抽象方法;
}
接口中成员的修饰符是固定的,都是公共成员。
常量: public static final
方法: public abstract
定义接口时如果修饰符没有写全,编译没问题,编译器会自动将缺失的修饰符补全。
特点:
1.不能实例化
2.需要有实现类,实现类需将接口中的方法全部实现,子类才能创建对象。
class 子类名 implements 接口名{}
3.支持多态 父接口类型的引用指向自己的实现类对象
4.接口中是没有构造方法的
类、接口间的关系:
类和类间关系:单继承
类和接口关系:多实现,接口名间使用逗号分隔即可
接口和接口关系:多继承
实际开发中:
class A extends B implements C,D{} 多见
class B implements C,D{}
class A extends B{}
接口和抽象类的区别
参数 | 抽象类 | 接口 |
---|---|---|
默认的实现方法 | 可以有默认的方法实现 | 完全是抽象的,根本不存在方法实现 |
实现 | 子类使用extends关键字来继承抽象类,如果子类不是抽象类的话,就需要重写抽象类中的所有方法 | 实现类使用implement关键字来实现接口,需要重写接口中的所有方法 |
构造器 | 可以有构造器 | 不能有构造器 |
与正常JAVA类的区别 | 除了不能实例化对象以外,和一个普通的类没有区别 | 是完全不同的构造类型,接口不属于类 |
访问修饰符 | 可以有public,protected,default修饰符 | 接口的默认修饰符是public ,不能使用其他的修饰符 |
main方法 | 可以有main方法-,并且我们可以运行它 | 没有main方法,因此不能运行 |
多继承 | 抽相方法可以继承一个类和实现多个接口 | 接口可以继承一个或多个替他接口 |
速度 | 比接口快 | 速度稍微有点慢,需要时间去寻找类中的实现方法 |
添加新方法 | 如果需要添加新的方法,可以提供默认的实现,不需要改变现在的代码 | 如果在接口中添加方法,必须改变实现该接口的类 |
抽象类是对对象属性和行为的抽象,通常用来抽象属性。
接口只是对对象的行为的抽象,不能用来抽象属性。
什么时候使用抽象类和接口
如果你拥有一些方法并且想让它们中的一些有默认实现,那么使用抽象类吧。
如果你想实现多重继承,那么你必须使用接口。由于Java不支持多继承,子类不能够继承多个类,但可以实现多个接口。因此你就可以使用接口来解决它。
如果基本功能在不断改变,那么就需要使用抽象类。如果不断改变基本功能并且使用接口,那么就需要改变所有实现了该接口的类。
15.内部类
1.概念
概念:将一个类定义到另一个类的里边,将里边的类叫做内部类或内置类。
描述两类事物时,发现这两个事物间应该有包含关系,这时可以使用内部类。
比如:教学类和教室 身体和心脏
2.分类
按照位置:成员内部类和局部内部类
按照有无类名: 有名内部类和匿名内部类
3.各类区别
成员内部类:
将类定义到另一个类的里边,位置即是类中方法外,可以使用成员修饰进行修饰。
默认、private、static
默认内部类:
类中成员: 非静态成员 和 静态常量
可以访问它所属的外部类中的成员
访问内部类中的成员,需创建内部类对象,方式有两种:
1.直接方式: 外部类名.内部类名 对象名 = new 外部类名().new 内部类名();
2.间接方式:
在外部类中定义方法,在该方法中创建内部类对象,调用内部类中成员。
在外部其他类中创建外部类对象,调用定义的方法。
私有内部类:
内部类前边使用private关键字修饰了,具体了私有特性,意味着只能在当前类使用。
类中成员: 非静态成员 和 静态常量
可以访问它所属的外部类中的成员
访问内部类中的成员,需创建内部类对象,方式只有1种:
间接方式:
在外部类中定义方法,在该方法中创建内部类对象,调用内部类中成员。
在外部其他类中创建外部类对象,调用定义的方法。
静态内部类:
内部类前边使用static关键字进行修饰了,因此具备静态特性。 别名:嵌套类。
类中成员:静态和非静态都可以定义
类中的静态方法只能访问内部类中的静态成员;类中的非静态方法能访问内部类中的静态成员也可以访问非静态。
由于类是静态的,只能访问它所属的外部类中的静态成员。
访问类中成员:
静态成员:
直接方式: 外部类名.内部类名.方法名
间接方式: 在外部类中定义方法,在方法中 内部类名.方法名
在外部其他类中创建外部类对象,调用该方法
非静态成员:
直接方式:new 外部类名.内部类名().方法名
间接方式:在外部类中定义方法,在方法中 new 内部类().方法名
在外部其他类中创建外部类对象,调用该方法
局部内部类:
将类定义到局部位置中,即方法中。
注意:该内部类不能使用成员修饰符修饰。
类中成员: 非静态 和 静态常量
可以直接访问它所属的外部类中的成员。
访问内部类中成员,需创建内部类对象,在它所在的局部位置中去创建。
注意:局部内部类访问它所在局部位置上的变量时,不能对该变量值进行修改,因为该
变量前边有final,jdk8以上不需要手动写final,编译器会自动补上。
匿名内部类
前提:存在一个类或者一个接口,这个类可以是具体的也可以是抽象的
格式: new 类名或者接口名(){
方法重写;
};
本质:一个继承了该类或者实现了该接口的匿名对象
建议:
\1. 子类中不要写自己特有方法
\2. 父类中或父接口中 都不要有太多需要重写的方法 不超过3个
//定义一个接口
public interface Inter {
void show();
}
//创建外部类和内部类,匿名实现一个接口
public class Outer4{
public void method(){
new Inter(){
@Override
public void show(){
System.out.println("匿名内部类");
}
}.show;
}
}
//也可以这样
public class Outer4{
public void method(){
Inter i = Inter new Inter(){
@Override
public void show(){
System.out.println("匿名内部类");
}
};
i.show;
}
}
//创建实例调用匿名内部类中的方法;
public class Outdemo{
public static void main(String[] args){
Outer4 o = new Outer4();
o.method();
}
}
成员内部类 默认内部类(前面不加修饰) | 成员内部类 私有内部类(前面private修饰) | 成员内部类 静态内部类(前面static修饰) | |
---|---|---|---|
类中成员 | 静态和非静态 | 静态和非静态 | 静态和非静态 |
访问内部类中成员 | 直接:外部类名.内部类名 对象名 = new 外部类名().new 内部类名(); 间接:在外部类中定义方法,在该方法中创建内部类对象,调用内部类中成员。在外部其他类中创建外部类对象,调用定义的方法。 | 间接:在外部类中定义方法,在该方法中创建内部类对象,调用内部类中成员。在外部其他类中创建外部类对象,调用定义的方法 | 静态成员: 直接方式: 外部类名.内部类名.方法名 间接方式: 在外部类中定义方法,在方法中 内部类名.方法名在外部其他类中创建外部类对象,调用该方法 非静态成员: 直接:new 外部类名.内部类名().方法名 间接:在外部类中定义方法,在方法中 new 内部类().方法名 |
内部类中的方法访问其他 | 可以访问外部类和内部类中的所有的成员 | 可以访问外部类和内部类中的所有的成员 | 内部类中的静态方法可以访问外部类和内部类中的静态成员 内部类中的静态方法可以访问外部类和内部类的静态和非静态成员 |
局部内部类 | |||
类中成员 | 静态和非静态 | ||
访问内部类中成员 | 可以访问外部类和内部类中的所有的成员 | ||
内部类中的方法访问其他 | 访问内部类中成员,需创建内部类对象,在它所在的局部位置中去创建。 | ||
注意: | 局部内部类访问它所在局部位置上的变量时,不能对该变量值进行修改,因为该变量前边有final,jdk8以上不需要手动写final,编译器会自动补上。 | ||
package和import关键字
package:
包的意思,创建一个包,相当于是电脑磁盘中的一个文件夹。
作用:
1.分类管理类文件
2.在不同包中可以出现同名类
3.可以将源文件和类文件进行相分离
告诉jvm当前类应该存储在那个地方。
语法:
package 包名;
规范: 小写单词或字母组成
公司域名倒置.项目名.模块名[.子模块]*;
例子: com.ujiuye.cms.login;
注意:该语句在一个源文件中只能出现一次
一定是在有效代码的最上边。
带包编译:
javac -d 目录 源文件名.java 自动创建包中的文件夹
注意:类中有package语句,那么类名有了限定,完整形式为:包名.类名
带包执行:
java 包名.类名
jvm启动执行时,默认导入的是java.lang包下的所有类,因此该包下的所有类直接使用,不需要import关键来进行导入。
import:
导入的意思。
告诉jvm,当前类中要使用的其他类去哪找。
语法格式:
import 包名.类名; 找指定的类
import 包名.*; 找指定包中的所有类
该语句位置是在package和class中间,可以出现多次。
jdk5.0特性:
静态导入:导入静态成员。
import static 包名.类名.静态成员名;
import static 包名.类名.*;
好处:简化代码书写,省略了:类名.
弊端:降低了代码的阅读性,不建议过多使用
模板设计模式
设计模式:
是前辈们对代码开发经验的总结,是解决特定问题的一系列套路。它不是语法规定,而是一套用来提高代码可复用性、可维护性、可读性、稳健性以及安全性的解决方案。
一共有23种设计模式。
根据目的划分: 结构型、行为型、创建型。
http://c.biancheng.net/design_pattern/
模板设计模式:
行为型模式中的一种。
将一个抽象类看成是一个模板,此时不能确定实现的逻辑使用抽象方法来表示,此时能明确逻辑实现的就使用具体方法,最终不能明确的由子类来实现,不同子类可以有不同实现方式。
总结:抽象类用来确定一个结构,不能确定部分有子类来实现。
六、API
1.object类
jvm启动,默认导入的是java.lang包中的内容,该包下的内容不需要import进行导入。
概述:
该类是java体系中的根类,所有对象都将该类作为直接或者间接父类
所有对象包括数组都继承了该类中的方法。
构造方法:
Object() :该方法中没有super()语句了。
方法:
boolean equals(Object obj) : 比较两个对象的地址值是否相同
该方法比较的是地址值,没有实际意义,通常会将该方法进行重写,比较有意义数据,通常是类中属性的比较。
== 和 equals区别:
==:
可以比较基本类型也可以比较引用类型
比较基本类型: 比较是数值是否相同
比较引用类型: 比较是的地址值
equals:
只能进行引用类型的比较,比较是地址值 通常会重写,比较属性
int hashCode() :返回对象的哈希码值
每创建一个对象,该对象都会有一个哈希值存在,默认不同对象(object类中的equals)哈希值不同,但是可以通过重写hashCode方法,让不同对象有相同的哈希值。因此该方法是不能判断是否是同一对象的。如果是同一对象的,哈希值一定相同。
String toString() :返回对象的字符串表示。
当打印对象名时,显示调用该方法和不调用打印的结果是相同的,因此打印对象名时这个方法是被自动调用的。
格式: 包名.类名 + @ + 哈希值
这种格式看不懂,建议重写该方法,显示易于看懂的信息,即属性信息。
Class getClass() :用于返回当前jvm正在运行时的类
注意:返回值类型是Class类型,Class是一个类类型。
JavaBean:
1.私有属性 2.无参构造 3.set和get方法
可选: 有参构造 重写toString
2.String类
概述:
1.该类是一个final类,不能有子类。
2.只要出现双引号表示的字面值数据,都是该类的一个实例对象,如“abc”
说明创建字符串对象,可以不使用关键字new。
-
字符串是常量,创建后不能改变,能改变的是引用的指向
-
由于字符串不能改变,因此被共享。
-
字符串底层原理就是字符数组
构造方法:
使用new关键字创建对象时,调用的方法。
单元测试:JUnit
定义方法: public void 方法名(){ ....}
需要在方法的上边加入 @Test 注解,需要导入对应的列库。
注意:项目中不要出现以Test为类名的类。
返回值 | 方法 | 作用 |
---|---|---|
String | String() | 初始化一个新的String对象,使其成为一个空的字符序列 |
String | String(byte[] byte) | 使用平台默认的字符解码器指定的byte数组,构造一个新的String |
String | String(byte[] byte,int 开始,int 个数) | 使用平台默认的字符解码器指定的byte数组,构造一个新的String,指定开始索引和个数 |
String | String(char[] value) | 字符数组转化为字符串 |
String | String(char[] value,int 开始,int 个数) | 字符数组转化为字符串,指定开始索引和个数 |
String | String(String orginal) | 创建一个新的字符串,是原来字符串的副本 |
判断 | ||
boolean | contains(字符序列“hello”) | 当这个字符串包含这个字符序列的时候返回true |
boolean | endswith(字符或者字符序列) | 判断字符串是否以指定的内容结尾 |
boolean | starwith(字符或者字符序列) | 判断字符串是否以指定的内容开始 |
boolean | equals() | 判断此字符串与一个字符串是否相等 |
boolean | equalsIgnoreCase() | 判断此字符串与一个字符串是否相等,不考虑大小写 |
boolean | isEpty() | 当length()为0 时返回true |
获取 | ||
char | charat(index) | 返回指定索引处的char值 |
int | indexof(int ch) | 返回指定字符在字符串中第一次出现的索引 |
int | indexof(int ch, int fromindex) | 返回指定字符在字符串中第一次出现的索引,从指定位置开始 |
String | subString(star,end) | 按照索引截取指定字符串 |
String[] | split("d") | 按照给定的字符串截取,返回一个字符串数组 |
3.字符串缓冲区对象
String 类型的数据存放在常量池,当创建一个对象时,如果常量池有的话就直接引用,如果没有的话就创建一个。每次对字符串操作就会开辟一个空间储存,比较浪费资源。
缓冲区:
看成一个容器,这个容器的大小可以改变。
字符串缓冲区:
操作过程中可以操作任意类型的数据,操作结束后,得到一个唯一的字符串。
在操作的过程中,一直操作同一个缓冲区。
对象:
StringBuffer和StringBuilder
二者的功能是相同的,
区别是:StringBuffer jdk1.0版本的,多线程安全,效率慢
StringBuilder jdk5.0版本的,多线程不安全,效率快
特点:都是final类,即不能有子类,可变的字符序列。
对象是围绕着 :增删改查进行功能设计的。
构造方法:
new StringBuilder() 常用
new StringBuilder(指定容量)
new StringBuilder(String str) 常用,将字符串转为字符串缓冲区对象
//创建默认字符串缓冲区,默认长度为16
StringBuffer s = new StringBuffer();
System.out.println(s.capacity());
//创建自带内容的字符串缓冲区,长度为默认+内容长度
StringBuffer s1 = new StringBuffer("ABC");
System.out.println(s1.capacity());//16+3
System.out.println(s1);
//创建指定容量的字符串缓冲区
StringBuffer s2 = new StringBuffer(20);
System.out.println(s2.capacity());
字符串和缓冲区对象之间的转换问题:
String---->StringBuilder : new StringBuilder(String str)
StringBuilder ---->String: new String(StringBuilder s)
new StringBuilder().toString()
互转的目的就是为了使用对方的功能或对方的特点。
方法:
增:
append(data) : 将data追加到原有数据的末尾
insert(index,data) :将data插入到index位置上
//增
s.append(123).append(1.23).append("sd").append(true); //1231.23sdtrue
s.insert(0,"w"); //w231.23sdtrue
System.out.println(s);
删:
delete(start ,end) :删除[start,end)区间内的字符
deleteCharAt(index):删除index位置上的字符
//删
s.delete(0,5); //删除字符串中的索引为0-4的元素
System.out.println(s);
s.deleteCharAt(0); //删除索引为0的元素
System.out.println(s);
改:
replace(start,end ,newStr):将[start,end)区间内的替换为newStr
reverse(): 反转
setCharAt(index, newChar) :将index位置上的字符修改为newChar
s.replace(0,2,"56"); //把字符串中的索引为0-1 的元素替换为56
System.out.println(s);
s.reverse(); //翻转所有的元素
System.out.println(s);
s.setCharAt(0,'s'); //把索引为0的元素替换为s
System.out.println(s);
查:
length(): 获取字符长度
capcity(): 获取实际容量
toString():返回字符序列
//查
System.out.println(s.length()); //查看字符串的长度
System.out.println(s.capacity()); //查看字符串的容量
System.out.println(s.toString()); //查看具体内容,结果是String 类型
System.out.println(s); //查看具体内容,结果是StringBuffer 类型
StringBuilder和String作为方法参数时:
public static void main(String[] args) {
String s = "abc"; // s指向abc
test(s);
System.out.println(s); //s的指向没有变,结果还是abc
}
public static void test(String str ){ //str = s
str = "123";
}
public static void main(String[] args) {
StringBuffer s1 = new StringBuffer("123");
test1(s1);
System.out.println(s1);
}
public static void test1(StringBuffer str){
str.append("abc"); //结果为:123abc 在原来的基础上添加
str = new StringBuffer("456"); // new了一个新的容器,和之前没有关系
}
包装类
java.lang包中的对象。
围绕着基本类型进行设计的,一共有8个对象。
因为基本类型仅仅是表示一个简单的数据,需要能像对象一样,进行方法和属性的访问操作。
基本类型:
byte short int long double float char boolean
包装类型:
Byte Short Integer Long Double Float Character Boolean
包装类用法基本是相似的,因此只要找一个常用的作为代表来学习即可----Integer。
特点:
这8个类都是final类,不能有子类。
只有字符类型有一个构造方法,来创建对象,其他对是两个与Integer类似。
以Integer为例
Integer i = new Integer(1); //int类型
System.out.println(i);
Integer i1 = new Integer("110"); //字符串类型,字符串内容必须是int类型的,否则会抛出数字格式化异常
System.out.println(i1);
格式之间的转换:
xxxValue(): 将对象转为xxx的基本类型
parseXxx(): 将字符串转为xxx的基本类型 Character类没有该方法
Integer i = new Integer(1);
int a =i.intValue(); //intValue() 将对象转换为int类型
System.out.println(a);
String s = "abc";
int b = Integer.parseInt(s); //parseInt() 将字符串转换为int类型
System.out.println(b);
1.字符串转换成包装类 1)可以使用包装类中的构造函数进行转换。 Integer(String s) 构造一个新分配的 Integer 对象,它表示 String 参数所指示的 int 值 Integer i1=new Integer("123"); 2)可以使用包装类中的valueOf()方法。 static Integer valueOf(String s) 返回保存指定的 String 的值的 Integer 对象。 Integer i2=Integer.valueOf("123");
2. 包装类转换成字符串
1)使用包装类的toString()方法; String s=Integer.toString();
3. 字符串转换成基本数据类型
1)字符串转成基本类型使用包装类中的parseXxxx方法。 static int parseInt(String s)
将字符串参数作为有符号的十进制整数进行解析。Character类没有这个方法
4. 基本数据类型转换成字符串类型 1)可以直接使用+号 String s=123+""; 2)使用String类中的valueOf static String valueOf(int i) 返回 int 参数的字符串表示形式。 String s=String.valueOf(int i);
注意:String参数一定要与被创建对象的格式是一致的,否则出现格式化异常。
例如: 将”11a”封装成Integer对象,出现NumberFormatException
Boolean对象创建是,参数是String的,参数值只要是true(忽略大小写),最终将
true封装成对象,其他字符串值都是false封装成对象。
总结:
int 、String、 Integer三者间转换:
int--->String : int+””
String.valueOf(int)
String---> int: Integer.parseInt(str)
int--->Integer : new Integer(int)
Integer.valurOf(int)
Integer---->int: intValue()
String---->Integer : new Integer(str)
Integer.valueOf(str)
Integer---->String : new Integer().toString()
谁变Integer :方法1 ---> new Integer(谁)
方法2 ---> Integer.ValueOf(谁)
谁变String :方法1 ---> .toString
方法2 ---> String.valueOf(谁)
方法3 ---> 基本类型+“”
谁变int : Integer.parseInt(str) 字符串
int: intValue() nteger
JDK5.0特性:
自动装箱和自动拆箱:
装箱:将基本类型转为包装类对象形式
拆箱:将包装类对象转为基本类型
自动装箱: 可以将基本类型数据直接赋值给包装类对象, new Integer()
自动拆箱: 可以将包装类对象直接赋值给基本类型变量, intValue()
好处:简化代码的书写
弊端:大量使用可能会对性能有损耗,因此不建议过多使用
4.System类
java.lang包中,final类,系统类,类中成员是静态的,该类不能实例化。
属性:
out: 标准的输出数据,默认输出位置是控制台,可以改。
in :标准的输入数据,默认是通过键盘进行输入,可以改。
err: 标准的错误数据输出,用法out相同,输出位置也是控制台,输出内容位置会移动。
方法:
long currentTimeMillis(): 获取当前系统时间毫秒值,从1970-1-1 0:0:0开始计算的。
1s = 1000ms
void exit(int status) :jvm终止执行。status是状态码,非0数字代表异常退出。
5.Math
java.lang包中,final类,类中封装了常用的一些基本数学计算,如三角函数、对数等。
类中成员都是静态的。
属性:
PI:圆周率
E: 自然底数
6.大数据类型
java.math包中。
BigInteger:
基本类型:long类型 8个字节
遇到的数据超出long范围,使用BigInteger来表示。
BigInteger b1 = new BigInteger("11");
//返回类型是一个BigInteger类型的
BigDecimal:
double、float 应用领域:科学记数或工业领域,都是近似数。
该类是一个不可变的有精确的表示小数
构造方法:
BigDecimal(String num) : 常用
BigDecimal(double num) : 可能出现不可预知的结果,因此不建议使用
将double数据转为字符串,再封装到BigDecimal对象中
7.日期对象
java.util包。
Date:
表示特定的瞬间,能精确到毫秒。
该类中的大部分方法都是已过时方法,有对应的替代。
方法:
//无参数构造方法
Date date =new Date();
System.out.println(date);
//Fri Jul 09 20:40:38 GMT+08:00 2021
//带参构造方法
Date date =new Date(45646154165l); //意思是起始时间1970/1/1 加上这么多毫秒
System.out.println(date);
//Sun Jun 13 15:29:14 GMT+08:00 1971
//setTime 表示1970/1/1 以后的多少毫秒以后的时间
date.setTime(45746164500l);
System.out.println(date);
//getTime 表示现在距离到1970/1/1过了多少
long a = date.getTime();
System.out.println(a);
Dateformat
Date date =new Date(45646154165l);
DateFormat df = DateFormat.getDateInstance(); //DateFormat.getDateInstance()创建一个实例对象
String ss = df.format(date); //.format将date转为String类型
System.out.println(ss); //1971-6-13
Date time = df.parse(ss); //.parse 将String转为Date
System.out.println(time); //Sun Jun 13 00:00:00 GMT+08:00 1971
getInstance() 这个函数得到的最终结果是简短的
SimpleDateFormat:
对日期进行格式化,允许使用自己指定的模式
Date date =new Date(); //无参构造
SimpleDateFormat sdf = new SimpleDateFormat();
String s = sdf.format(date); //将Date值格式化
System.out.println(s); //输出是默认值 21-7-9 下午9:13
SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy年MM月dd日 hh:mm:ss E"); //自定义格式
String s1 = sdf1.format(date); //将Date值格式化为自定义的格式
System.out.println(s1); //输出指定格式 2021年07月09日 09:13:42 星期五
SimpleDateFormat:格式化和解析日期
1.格式化(Date 到 String ) : format(Date date)
2.解析(String 到 Date) : parse
8.日历对象
在java.util包中。
Calendar:
该对象将Date类中的大部分方法替代了。该对象封装有关系时间日期信息很详细。
获取Calendar对象:
static getInstance()
方法:
int get(字段) :根据字段获取字段值,字段:年、月、日...
Calendar c = Calendar.getInstance(); //创建日历对象
System.out.println(c.get(Calendar.YEAR)); //get 方法获取字段年
c.set(Calendar.YEAR,2022); //set 方法设置字段值
long l = c.getTimeInMillis(); //获取毫秒值
System.out.println(l);
总结
1.Date和Calendar互转
(1) Calendar转化为Date Calendar cal=Calendar.getInstance(); Date date=cal.getTime();
(2) Date转化为Calendar Date date=new Date(); Calendar cal=Calendar.getInstance(); cal.setTime(date);
2.获取毫秒的方法;
a.System currentTimeMillis()
b.new Date().getTime
c.c.getTimeInMillis() c是日期的一个实例化
NumberFormat
NumberFormat nf =NumberFormat.getInstance(); //创建一个实例化对象
nf.setMaximumIntegerDigits(2); //设置格式化格式
String s1 = nf.format(202.12); //开始格式化
System.out.println(s1); //02.12
9.异常
概念:
程序执行过程中出现了不正常情况,导致程序停止运行了。
不正常:代码出错了
理解:
异常也是对象,对象封装了代码错误的原因、位置、名称等相关信息。
异常也是一种处理异常的机制,包括:捕获、抛出、跳转等。
异常不同,对象不同,因此有一个继承体系(java.lang):
根类:
Throwable:
--Error :错误,比较严重的问题,不建议去捕获或处理。
--Exception:异常,比较不太严重的问题,建议去捕获处理。
异常(Exception)分类:
编译时异常(受检时异常):在编译时就检测的异常,必须处理后才能去执行。说明程序可能出现异常,但是不一定真的会出现异常
Exception中除了RuntimeException以外的异常。
运行时异常(非受检时异常):在运行时去检查,出现问题后停止执行,并将信息打印。
RuntimeException及其RuntimeException的子类
jvm默认处理异常的方式:
当执行到某行时,该行代码有问题,会找到异常体系中的一个对象来封装该问题,首先先尝试内部解决,能解决就解决,不能解决就交给调用者即上一级,上一级接到问题后,也是先尝试自己解决,能解决就解决,不能解决就交给调用者即上一级,...以此类推,最终交给jvm,jvm也会尝试自己解决,不能解决就采用默认处理方案,将异常问题等信息打印,并终止程序的执行。
异常处理:
1.捕获 自己解决
2.声明 找上一级
捕获
try{}: 可能出现异常的代码
catch{}: 处理异常代码
finally{}: 一定会执行的代码,作用用来做释放资源的操作。
常用方法:getCause(): 获取属性cause的信息,如果不存在返回null
getMessage():获取属性message的值
toString(): 返回throwable的简短描述
printStackTrace():打印输出Throwable的跟踪信息
格式1:
try{
}catch(异常类型名 变量名){
}
try中有异常,会有一个异常对象产生,将异常对象交给catch,catch接到后与小阔号中的异常类型进行匹配,匹配上就处理异常,如果没有匹配上就jvm默认处理。
public class Yichang {
public static void main(String[] args) {
System.out.println("开始");
try {
method(); //调用方法出现异常
}catch (ArrayIndexOutOfBoundsException e ){
// System.out.println("假装处理了");
e.printStackTrace(); //打印异常信息,虽然也会出现异常,但是程序在出现异常后不会停止
}
System.out.println("结束");
}
//创建方法
public static void method(){
int[] arr = {1,2,3};
System.out.println(arr[3]);
}
}
e.printStackTrace(); //异常信息输出在控制台
e.getMessage(); //返回详细消息字符串
e.toString(); //抛出简短描述
格式2:
try{
}catch(异常类型1 变量名1){
}catch(异常类型2 变量名2){
}...
try中有异常,会有一个异常对象产生,将异常对象交给catch,catch接到后与小阔号中的异常类型1进行匹配,匹配上就处理异常,整个语句块结束,执行try-catch后的代码,如果没有匹配上,与异常类型2进行匹配,....所有异常类型都没有匹配,jvm默认处理。
注意:catch小阔号中的异常类型,有父子关系,那么先写子后写父。如果没有父子关系即是兄弟关系,没有顺序之分。总结:从上往下看,类型可以逐渐变大或者不变。
格式3:
try{
}catch(){
}...
finally{
}
一个try一个catch一个finally
一个try多个catch一个finally
try中无论是否有异常,finally一定会执行。
即使遇到return;语句,finally也一定会执行。
只有一种情况,finally不执行,遇到System.ext(0);
格式4:
try{
}finally{
}
这种语句格式目的就是为了使用finally,因为finally不能独立出现。
catch中的代码:
只要是符合java的语法都可以,但是实际是什么问题什么解决方案。
比如: 语句、调用方法、创建对象
try-catch是允许嵌套使用的。
自定义异常
原因:
1.异常体系太庞大,不方便记忆和使用
2.异常体系中没有所需要的异常
步骤:
1.定义类继承Exception或RuntimeException
类名: 异常原因名+Exception
2.调用父类的构造方法(可选)
重写方法时,throws注意
\1. 重写方法时,父类方法没有throws,子类重写时可以不带有,如果带有throws,其后边只能跟RuntimeException,可以写多个
\2. 重写方法时,父类方法有throws,子类重写没有throws可以,如共有throws,只要是父类异常的子集或相同都可以。
总结:重写方法,可以没有throws,如果有throws范围只要不超过父类异常即可