方法
方法是定义在类中的一段独立代码,能完成某个事情。
定义方法时,提供方法的名称、返回值类型、参数列表,这三点称为方法三要素,定义的方法都需要这三部分。
当再使用该方法中的代码时,只需通过该方法名称调用即可。
方法能够减少代码冗余。
调用方法
通过类名调用
Math类
Math类时Java中的工具类,用于数学计数。
该类中的方法和属性都使用static修饰的,可以直接通过类名调用。
在任何类中,通过快捷键alt+7,展示方法列表。
//常用方法属性
System.out.println(Math.PI);// 圆周率
System.out.printlin(Math.E);// 自然常数
System.out.println(Math.abs(-5));// 绝对值
System.out.println(Math.max(1,2));// 最大值
System.out.println(Math.min(2,3));// 最小值
System.out.println(Math.ceil(2.1));// 3 向上取整
System.out.println(Math.floor(3.9));// 3 向下取整
System.out.println(Math.round(-1.5));// -1 四舍五入
System.out.println(Math.random());// [0,1] 直接的随机数
System.out.println(Math.sqrt(9));// 3 平方根
Systrm.out.println(Math.cbrt(27)); // 3 立方根
System.out.println(Math.pow(2,3));// 2的3次幂
通过对象调用
创建对象:类名 对象名 = new 类名([参数]);
Scanner sc = new Scanner(System.in)
sc.方法名();
Random rd = new Random();
rd.方法名();
3.在同一个类中,方法A直接调用方法B
class Test{
void funA(){
funB;
}
void funB(){
System.out.println("我是B方法");
}
}
方法的调用
调用方式
通过类名调用
通过对象调用
直接调用
参数
无参数
Scanner sc = new Scannner(System.in);
sc.next();// 调用无参数方法
有参数
Random rd = new Random();
rd.nextInt(); // 调用有参数方法
返回值
没有返回值,方法名的前面用void表示
calss Test{
void funB(){
System.out.println("我是B方法");
}
public static void maia (String[] args){
Test t = new Test();
t.funB();
}
}
有返回值
Random rd = new Random();
int num = rd.nextInt(10);
自定义方法
方法的三要素
方法名
使用驼峰命名法
方法返回值类型
如果有返回值,使用Java中的任意数据类型,方法体中使用return关键字返回对应类型的数据
如果没有返回值,使用void关键字
方法参数
参数写法:数据类型 形参名,数据类型 形参名
[修饰符] 返回之后类型 方法名(参数列表){
方法体;
}
方法的类型
无参数无返回值
void 方法名(){
// 方法体
return; // 遇到return立即结束方法
}
无参数有返回值
int 方法名(){
return new Random().nextInt();
}
有参数无返回值
void 方法名(数据类型 形参名,数据类型 形参名){
// 方法体
return;
}
有参数有返回之后
// 生成a,b中包含最小值,不包含最大值范围内的随机数
double rand (int a ,int b){
double num = Math.floor(Math.random()*Math.abs(a-b)+Math.min(a,b));
return num;
}
注意
有返回值的方法,必须要在方法体中加入return并能够执行,同时要return一个该方法返回值类型对应的数据
没有返回值的方法,可以不加return关键字。如果加入return关键字,不能跟上数据
方法中出现return,会立即结束方法,所以return语句之后不能再有代码
定义方法时的参数称为形式参数,简称形参,调用方法时,实际传递的参数称为实际参数,简称实参,实参只需要保证数据类型和形参相同即可。
编程思想
面向过程编程
Procedure Oriented Programming 简称POP
是一种基本的编程思想,将一件事情按流程按步骤执行,逻辑清晰。
每一步都是基于上一步的流程去继续实现。
注重于分析问题的步骤
如果逻辑复杂,如xxx管理系统,使用POP就会变得很玛法
C语言就是一门面向过程的编程语言
面向对象编程
Object Oriented Programming 简称OOP
是一种编程思想,核心是创建解决问题的对象,赋予对象行为和特征,让这些对象互相配合执行。
每个对象的行为实际也是面向过程
注重于全局如何创建完成某件事情的对象,如果适时的调用
这种思想致力于将计算机中的世界,描述的和现实中一致的思想
如洗衣服
pop:得到衣服-得到洗衣服-洗-晾晒
oop:得到衣服对象、得到洗衣机对象、调用洗衣机对象的洗衣服行为
总结
面向过程:亲力亲为,侧重于分析完成事情的过程
面向对象:所有事情交给相应的对象完成,侧重于如何创建解决问题的对象
类和对象
类Class
具有相同属性和行为的对象的集合。相当于模板。
属性
描述这个类的特征值,在程序中,通过定义变量实现
行为
描述这个类的动作,在程序中,通过定义方法实现’
创建一个class文件,就是创建一个类
定义类
[修饰符] class类名 {
// 属性(定义变量)
// 行为(定义方法)
}
/*
*定义车的模板
*属性:变量
*品牌
*颜色
*座位数
*排量
*
*行为:方法
*跑
*说话
*飞
*/
public class car{
//定义变量 数据类型 变量名;
String brand;
String color;
int seat;
// 定义方法
void run(){
System.out.println("车在跑。。。");
}
void introduce(){
// 在方法中可以直接访问同一个类中的属性
System.out,println("我是一辆车"+brand+"牌的"+color+"色的"+seat+"座车");
}
}
对象Object
对象由某个类创建出来的具体实例
创建对象
类名 对象名 = new 构造方法([参数]);
创建出的对象,通过 "." 操作符访问类中的非私有属性和方法
public class Test{
public static void main(String[] args) {
// 创建Car类的对象
// 类名 对象名 = new 类名();
Car benz = new Car();
// 对象.类中的属性和方法
benz.seat = 5;
benz.color = "白";
benz.brand = "奔驰";
benz.introduce();
benz.run();
}
}
类和对象的关系
对象是类的具体表现,类是对象的模板。
如制作月饼的模具就是一个类,每次用这个模具创建出来的月饼就是一个对象。
先定义类,才能通过该类获取对象
成员变量和局部变量
成员变量
定义在类中的变量,称为成员变量,有默认值。
![](https://i-blog.csdnimg.cn/blog_migrate/6957b01a0125b19cbc090932330925fa.png)
![](https://i-blog.csdnimg.cn/blog_migrate/60f42f1e98204efa9a0bde3c4493dd8c.png)
局部变量
定义在方法中的变量,称为局部变量。没有默认值,赋值后才能使用。
![](https://i-blog.csdnimg.cn/blog_migrate/e2d697e1b290bd088f6c6125fc7c7aaa.png)
成员变量和局部变量相关面试题
简述成员变量和局部变量的区别以及生命周期
成员变量是定义在类中的变量,有默认值,不赋值也能使用
局部变量是定义在方法中的变量,没有默认值,需要赋值后才能使用
成员变量的生命周期:类创建对象,成员变量就会初始化;类的对象被回收,成员变量就会销
毁
局部变量的生命周期:方法调用,对局部变量赋值,局部变量初始化,方法调用结束,局部变
量失效。
class Person{
String name;//成员变量,String是类类型,属于引用类型,默认为null
int age;//整型,默认0
double[] list;
void fun(){
System.out.println(name);//这里能通过编译,可以使用name,输出null
System.out.println(list[0]);//这里能通过编译,由于list为null,会报空指针异常
}
}
class Test{
public static void main(String[] args){
int num;//定义在方法中的变量称为局部变量,赋值后才能使用
System.out.println(num);//无法通过编译
}
构造方法
概念
构造方法也称为构造函数、构造器、constructor
它是一个特殊的方法。
没有返回值部分,方法名和类名一致,在创建对象时通过new调用,给类的成员变量赋值。
![](https://i-blog.csdnimg.cn/blog_migrate/3d3d905eec2b2e462f88b2eda55e457a.png)
特点
创建对象时必须通过new配合构造方法
构造方法没有返回值部分,名称和类名相同
构造方法可以存在多个,但是参数不能相同。这些构造方法之间的关系称为方法重载
每个类默认有一个隐藏的无参数的构造方法,方法体中隐含了一句super()。用于创建无参数的对象
如果自己写了带参数的构造方法,默认无参数的构造方法就会失效。如果想要同时拥有带参数和不
带参数的构造方法,
就需要再次显式地写出来
带参数的构造方法常用于初始化成员变量(给类中的变量赋值)
构造方法可以限制创建对象时携带的参数
构造方法无法通过"."操作符访问,只能通过new关键字创建对象时调用
IDEA中自动生成构造方法
在类空白处右键generate或快捷键alt+insert
![](https://i-blog.csdnimg.cn/blog_migrate/8ace0d537438b57eebff58854d135357.png)
在弹出的窗口中,选择Constructor
![](https://i-blog.csdnimg.cn/blog_migrate/4618e5996e0420740e52da858c5bc940.png)
选择生成的构造方法的参数,全选ctrl+a
![](https://i-blog.csdnimg.cn/blog_migrate/b15e82108d881fc42f05295c03236d58.png)
面向对象语言的三大特性--封装
封装
使用private关键字对成员变量进行修饰。再提供一组get和set的方法,用于对该属性读取和赋值。
可以防止除自身类之外的地方对private修饰的属性进行访问。
这样就能保护关键属性或给属性赋一个合理的值。
步骤
1.创建类,编写成员变量,对成员变量使用private修饰
![](https://i-blog.csdnimg.cn/blog_migrate/90818df53f4488235062412bbbf66158.png)
2.给所有成员变量添加set方法,用于赋值
![](https://i-blog.csdnimg.cn/blog_migrate/9d358d55eaffa026a12b7511fd9de9e3.png)
3.给所有成员变量添加get方法,用于读取
![](https://i-blog.csdnimg.cn/blog_migrate/0c9d2cf8d8f60508746905df5bee313b.png)
IDEA中自动生成getter/setter方法
在类中空白处右键generate或快捷键alt + insert,在弹出的窗口中选择getter and setter
![](https://i-blog.csdnimg.cn/blog_migrate/1675217a243c0f14f9dbd8ff72f20245.png)
在弹出的窗口中,选择要生成get和set方法的成员变量
![](https://i-blog.csdnimg.cn/blog_migrate/574933a7b6a6174360062c5c16c1fe00.png)
面向对象三大特性--继承
概念
类B使用extends(延伸)关键字"继承"类A。
语法:class 类B extends 类A{}
类B称为类A的子类,衍生类,subClass
类A称为类B的父类,超类、supClass
继承后,子类就能访问父类中的非私有(没有使用private修饰)成员变量和成员方法。
![](https://i-blog.csdnimg.cn/blog_migrate/593c0953b94a346c90e7a7af808ff0ec.png)
将多个类中的公共代码提取出来保存到一个公共类中,这些类使用extends"继承"这一个公共类,从而减
少这些类中的冗余代码。
如猫类、狗类都有类型、昵称等属性,也有吃、睡等方法,那就可以定义一个动物类,将这些公共的属
性和方法定义在动物类这个父类中,
再让猫类和狗类这些子类继承动物类。这样就能直接通过子类访问父类中的内容。
特点
如果多个类之中有相同的代码,可以将这些代码提取出来到一个公共的类中,这个类就是父类。再
让那些类去extends继承这个父类,那些类就是子类。子类就无需再写重复代码
子类中或子类对象可以直接访问父类中非私有(不用private修饰)属性和方法
创建子类对象时,会先执行父类中相应的构造方法
子类继承父类后,通常会对对父类中的方法进行拓展或覆盖,这称为方法重写。重写后,子类再调
用该方法时,执行的是重写后的内容
Java中是单继承。一个子类只能extends一个父类,一个父类可以有很多子类
Java中可以多重继承,类A可以继承类B,类B继承类C,这是类A既是类B的子类,也是类C的子
类,类A可以访问类B和类C中的非私有成员
任何类都是Object类的子类
方法重写和方法重载
方法重写override
当子类继承父类后,可以对父类中的方法进行扩展或覆盖。这个过程称为方法重写。
方法重写要求
方法名、返回值、参数列表必须和父类一致
访问权限不能比父类更严格(访问修饰符的范围要么一致要么更大)
不能抛出比父类更大的异常
IDEA中如果要重写方法,使用CTRL + O在弹出的窗口中选择要重写的方法
方法重载overload
在一个类中,如果多个方法的方法名相同,参数列表不同时,这些方法称为重载的方法。
同名不同参。
重载用于,在一个类中,某个方法在不同的条件下,执行不同的内容。
方法重载要求
方法名相同
参数必须不同(数量、类型)
与返回值无关
重载和重写相关面试题
说出重载与重写的异同
相同点:方法名不变
不同点:
重载在一个类中,重写在继承关系中子类重写父类
重载参数必须不同,重写参数必须相同
重载返回值无要求,重写返回值必须相同
构造方法能重载吗?能重写吗?构造方法可以重载。构造方法不能重写。
构造方法在执行时,一定会创建对象吗?
不一定。创建子类时会自动执行父类构造方法,但不会创建父类对象。
以下代码执行会输出什么结果
![](https://i-blog.csdnimg.cn/blog_migrate/138d25da174954a88b3a6e7f4f6ca99b.png)
this和super关键字
这两个关键字,都可以当做对象使用,也可当做构造方法使用。
当做对象使用
用法:this.属性或this.方法,super.属性或super.方法
此时的this表示当前类的对象,super表示当前类的父类对象
![](https://i-blog.csdnimg.cn/blog_migrate/15072a33e8210e100a0ad3086c53b6d4.png)
当做构造方法使用
用法:this([参数])或super([参数])
此时的this([参数])表示当前类的某个构造方法。如this()表示当前类的无参构造方法。
super([参数])表示当前类的父类的某个方法。如super()表示当前类的父类的无参构造方法。
如果当做构造方法使用时,只能写在另一个构造方法的第一行。
![](https://i-blog.csdnimg.cn/blog_migrate/69f662960899234e5132949c32de523f.png)
注意
如果父类中有无参数的构造方法,在子类的构造方法中,可以不写super(),默认自动调用。
如果父类中有带参数的构造方法,没有无参数的构造方法,在子类的构造方法中,必须要有super([参
数])。
父类和子类中都没有构造方法(只有默认的无参构造方法)
![](https://i-blog.csdnimg.cn/blog_migrate/46c3d76dad5cba6c0ed72a75d3d53275.png)
父类中没有无参构造方法,子类中就必须调用父类中对应的构造方法
包package
通过包可以将.java源文件进行结构化管理,相当于windows中的文件夹。
不同的包中,可以保存相同的.java源文件。
某个类在某个包中时,会在该类的代码最上加入 package 包名 ;
包的命名
包名通常使用公司域名的倒序形式。
如baidu.com是百度的域名,有一个test的项目,包名写为com.baidu.test
包名中的".",相当于进入文件夹
如com.baidu.test,会创建3个文件夹:com下有baidu,baidu下有test。
![](https://i-blog.csdnimg.cn/blog_migrate/30bb3430a51f1e0e2563d234e299130a.png)
导入包
如a包中的类要使用b包中的类时,需要在a包中的类中,导入b包或b包中的某个类。
如在使用Scanner时,就需要导入Scanner所在的java.util包。 import java.util.Scanner;
在IDEA中,如果是通过自动补全的形式写的代码,会自动导入该类,
或设置自动导包删包。
![](https://i-blog.csdnimg.cn/blog_migrate/7e50beb892e70fb4bf69b7f6c7d1cad7.png)
如果需要手动导入包,在报错的位置上按下快捷键alt+回车,
如果多个类,类名相同但在不同的包中,使用该类时选择合适的包。
访问修饰符
访问修饰符可以限制某个类、属性或方法的访问权限
用法:
修饰类:访问修饰符 class 类名{}
修饰属性:访问修饰符 数据类型 变量名;
修饰方法:访问修饰符 返回值类型 方法名(){}
![](https://i-blog.csdnimg.cn/blog_migrate/aa7936743cc12d9af05fd0f77f3fceb8.png)
访问权限表
![](https://i-blog.csdnimg.cn/blog_migrate/da79ba53131e525b11a22fa480426977.png)
访问权限从大到小
public >>> protected >>> 默认的 >>> private
final关键字
修饰属性
当final修饰属性时,该属性的值不可更改,这个属性称为常量。
常量在程序运行过程中,保存的值不能编号,所以定义常量时需要初始化。
常量名所有字母大写,多个单词之间用_隔开。
![](https://i-blog.csdnimg.cn/blog_migrate/ee1e89926196c6746dfefe4567f608a6.png)
修饰方法
当final修饰方法时,该方法不能被重写。
在方法的返回值前加上final。
![](https://i-blog.csdnimg.cn/blog_migrate/cf560425a9006b48d955e270cfdcb17e.png)
修饰类
当final修饰类时,该类不能被继承。
定义类,在class前加final
![](https://i-blog.csdnimg.cn/blog_migrate/c4fde5250f012f9d87fa38a546c68d1c.png)
创建对象时的内存变化
![](https://i-blog.csdnimg.cn/blog_migrate/aed28998f3c03608c9f636cd71345b1e.png)
Object类
是java中所有类的父类。每个类都是这个类的子类,但没有使用extends体现出来
该类中定义了很多方法,通常需要进行重写。
![](https://i-blog.csdnimg.cn/blog_migrate/af13404776b1577eee77ba259621e470.png)
对象造型/对象转型/cast
类似于原始类型中的数据类型转换。对象A转换为对象B的过程,称为对象转型。
在非继承关系的两个对象中,无法转型。
向下转型
父类对象转换为子类对象的过程,称为向下转型。强制转换
![](https://i-blog.csdnimg.cn/blog_migrate/47021921e12311f25c2212a0f4d00cd8.png)
向上转型
子类对象转换为父类对象的过程,称为向上转型。自动转换
![](https://i-blog.csdnimg.cn/blog_migrate/de990952a2e07ee72c8da573e643d04e.png)
重写equals方法
//一个父类对象
Object obj = new Object();
//默认无法直接将obj使用Person对象接收
//"强制转换"
Person p = (Person) obj;
//一个子类对象
Person p = new Person();
//默认子类对象可以用父类变量接收 多态
Object obj = p;如果两个对象的属性全部相同,在日常的业务逻辑中,可以视为这两个对象是同一个对象。
但是默认使用new创建的对象,就算属性一致,也是不同的内存地址,
如果用==比较,比较的是对象的内存地址,地址不同,返回false。
所以对象比较相同不能使用==
这时就需要自定义一套比较的方法,Object中有一个equals方法,用于比较两个对象是否相同,
但是Object中的equals方法用==比较,所以对该方法进行重写。
如两个Student的id、name、sex都一致,返回true.
![](https://i-blog.csdnimg.cn/blog_migrate/f7efc05a7c2cddadea4eafbe48989da9.png)
在IDEA中自动生成equals方法
在类中右键generate或快捷键alt + insert,选择equals and hashcode,选择属性。
如两个对象的id相同就视为同一个对象,可以只选择id属性;
如两个对象的所有属性相同才视为同一个对象,选择全部属性。
同时生成的hashcode()可以删除。
面向对象三大特性--多态
子类的对象保存在父类的变量中。
父类 变量 = new 子类();
![](https://i-blog.csdnimg.cn/blog_migrate/217fd70c9c03ec17f627f5a914021e01.png)
多态的应用
当某个方法的参数为父类变量时,可以传递一个子类对象。
这样就能在传递不同的子类对象时,表现出不同的形态。
如 要定义动物发出叫声的方法,参数是猫,输出猫对象的叫的方法"喵喵",参数是狗,输出狗对象的叫
的方法"汪汪"。
不用多态,需要写很多重载的方法,参数为猫或狗或其他类型。
使用多态,只需一个方法,参数为动物类,在动物类中定义叫的方法,让子类猫类狗类对其进行重写。
这时调用动物的叫的方法,实际会根据动物子类对象,调用具体子类重写后的方法。
多态的前提
在继承关系中
父类的变量保存子类的对象(向上转型)
abstract抽象的
修饰方法
使用:访问修饰符 abstract 返回值类型 方法名(参数列表);
如果一个方法的方法体无法描述,是由其子类进行重写后使用,可以将这个方法定义为抽象方法。
该方法就可以去掉方法体部分,该方法的所在类,也必须是一个抽象类,使用abstract修饰。
修饰类
使用:访问修饰符 abstract class 类名{}
如果一个类中有抽象方法,这个类必须也是一个抽象类
![](https://i-blog.csdnimg.cn/blog_migrate/fb1e0b3c5d721a4d94743e34056e73ca.png)
abstract关键字特点
修饰类:被修饰的类称为抽象类
抽象类不能被实例化(不能创建对象);
抽象类中有构造方法,在创建其子类对象时自动调用。
抽象类中可以有普通方法,通过其子类对象主动调用。
抽象类中定义的所有抽象方法,子类要么全部进行重写,要么也定义为抽象类。
修饰方法:被修饰的方法称为抽象方法
抽象方法没有方法体
抽象方法只能出现在抽象类中
abstract不能修饰构造方法和静态方法
抽象相关面试题
抽象类的特点?
抽象类是使用abstract修饰的类,除了不能创建对象、能定义抽象方法外,与普通类一样。
抽象方法的特点?
抽象方法是使用abstract修饰的方法,没有方法体。非抽象子类必须要对父类中的抽象方法进
行重写。
//当一个类中有抽象方法时,这个类也必须是抽象类
public abstract class Fruit{
//当一个方法没有方法体时,这个方法定义为抽象方法
public abstract void eatIt();
}抽象类中有构造方法吗?
有构造方法,但不是通过new该类对象时调用,而是在new其子类对象时自动调用。
执行某个类的构造方法时,一定会创建这个类的对象吗?
不一定
如果是普通类,在执行构造方法时,一定会创建对象
如果是抽象类,在执行构造方法时,不会创建自身对象,只会创建其子类对象
接口interface
在Java中,数据类型分为基本类型和引用类型。
引用类型包含:数组、类和接口。
所以接口是一种数据类型,类似于类,在定义接口的时候,使用interface替换class。
由于Java是单继承,如果类A既要继承类B中的内容,也要继承类C中的内容时,
如果用"extends class名",只能选择一个类继承,
但使用implements interface名1,interface名2...就能同时"继承"多个"父类".这里的"父类"就是接口。
通常用extends表示类A继承类B,用implements表示类A实现接口A,接口B...
一个类可以同时implements实现("继承")多个接口。
extends和implements
类A extends 类B
类A当做类B的子类,称为继承
类A implements 接口A,接口B...
类A当做类B的实现类,称为实现
接口A extends 接口B
接口A继承接口B类A extends 类B implements 接口A,接口B...
类A是类B的子类,同时也是接口A,接口B的实现类
什么时候使用接口
如果想要让某个类作为多个"类"的子类时,将这些"父类"定义为接口
如果某个类中的所有方法都是抽象方法时,将这个抽象类改为接口
定义接口
![](https://i-blog.csdnimg.cn/blog_migrate/ef5533ddd058993ed1925af6ac2656fd.png)
抽象类和接口的异同
抽象类是一个类,用abstract class定义
有构造方法,不能创建对象,在创建子类对象时自动调用父抽象类中的构造方法
抽象类中可以有非抽象方法
抽象类被子类继承时,用extends关键字。子类需要重写父抽象类中的所有抽象方法
子类只能继承一个抽象类
抽象类中可以定义成员变量
接口不是一个类,用interface定义
没有构造方法,不能创建对象
接口中定义抽象方法时,无需加public abstract修饰符
接口中可以存在被default或static修饰的方法
接口被子类实现时,用implements关键字。子类需要重写父接口中的所有抽象方法
子类可以实现多个接口,用逗号隔开
接口中定义的属性都是公共的静态常量,被public static final修饰,必须要有初始值
相同点
接口和抽象类都无法创建对象
接口的实现类和抽象类的子类,都需要重写抽象方法
接口是一个完全抽象类。JDK1.8之后可以在接口中定义有方法体(被default或static修饰)的方法。
package com.hqyj.test3;
/*
* 模拟电脑使用USB设备
* 主机都有"USB接口",定义主机类,定义一些方法,参数为"USB设备"
* 所有“USB设置”都有连接和退出功能
*
*
* */
public class Main {
public static void main(String[] args) {
Computer computer = new Computer();
//接口对象无法实例化(无法创建对象)
//USB usb = new USB();
//创建接口的实现类对象,可以用自身接收,也可以用父接口变量接收
Mouse mouse = new Mouse();
USB keyboard = new Keyboard("罗技");
computer.powerOn(mouse, keyboard);
//可变参数的方法传递参数时,可以是任意数量个参数,但这些参数类型必须统一
computer.powerOff(mouse,keyboard);
}
static静态的
每次new创建一个对象,都会在堆空间中开辟一块区域,这个过程是需要花费时间和空间的。
在栈空间中,只会定义变量,保存堆空间中某块区域的地址。通过变量访问堆空间中对应地址的数据。
如果多个对象都有相同的属性或方法时,可以将这些公共的属性和方法使用static修饰,
让其成为静态数据,在类加载的时候就保存在静态区中
在不使用静态成员时
![](https://i-blog.csdnimg.cn/blog_migrate/a6ec22987519850fb4ed486e721d5f5c.png)
如上图的"重庆大学"这个字符串,每个对象都会使用,就可以将其使用static关键字,定义为静态属性。
静态属性或静态方法,在类加载时就会保存到内存中,无论是否创建对象都能访问,通过类名直接访
问。
使用静态成员时
![](https://i-blog.csdnimg.cn/blog_migrate/2760ada8a555734244bd5ab9d6ff588d.png)
概念
static是一个修饰符,可以修饰属性、方法、代码块。
被static修饰的内容,称为静态成员。静态成员在类加载时就保存到内中。
访问静态成员时,可以不用创建对象,直接通过类名访问。
如Math中的所有属性和方法,都是静态的,都通过Math直接访问。
定义和访问
![](https://i-blog.csdnimg.cn/blog_migrate/153a553f2f7317f4d7f1d7568ad61a76.png)
什么时候使用static
如果某个属性或方法被高度重用时,可以将其定义为static静态的。
这样这些属性和方法在类加载时就会加载到内存中,从而直接通过类名即可访问。
static特点
静态方法中只能使用静态成员,不能使用非静态成员
![](https://i-blog.csdnimg.cn/blog_migrate/0f2c22a1158eb71709f0914aa622c395.png)
非静态方法中,可以访问非静态或静态成员
![](https://i-blog.csdnimg.cn/blog_migrate/c9f06ab6651fd67266fd40ccbef7025c.png)
静态方法中不能使用this或super关键字
成员变量、局部变量、静态常量
成员变量:定义在类中的变量
成员变量随着对象的创建而存在,随着对象的回收而销毁。
作用范围在类内部,成员变量有初始值。
局部变量:定义在方法中的变量
局部变量随着方法的调用而存在,随着方法执行结束而销毁。
作用范围在方法内容,局部变量没有初始值,必须赋值后才能使用。
静态常量:被final、static修饰的成员变量
静态常量随着类加载而存在,随着类的销毁而销毁(通常程序运行结束).
作用范围在程序运行周期中,静态量有初始值,静态常量必须赋值。
可变参数
当某个方法的参数是同一种类型且数量未知时,参数列表中可以使用可变参数定义
![](https://i-blog.csdnimg.cn/blog_migrate/8939fef69b53c29e66fb215f7b756447.png)
特点
可变参数只能出现一次,且是最后一个参数
可变参数实际是一个数组
调用参数为可变参数的方法时,传递的实参要使用逗号隔开
![](https://i-blog.csdnimg.cn/blog_migrate/faa78f991fec7d57b97780d95dc2804b.png)
枚举
Java中的枚举是一个特殊的类,是一些常量的集合。
如星期可以用数字1-7表示,也可以用"周一到周天"表示,
也可以用SUN,MON,TUE,WED,THU,FRI,SAT这些来表示。
这三种都可以称为枚举,对星期这个概念进行枚举。
定义枚举类型
![](https://i-blog.csdnimg.cn/blog_migrate/856ae2e455d7f8b8845c6a711c171d3c.png)
内部类
内部类,是指定义在类中的类。
内部类通常使用private修饰,定义在类中,用于隐藏类的实现细节,将类进行封装
![](https://i-blog.csdnimg.cn/blog_migrate/c652c6157f4a75bd2e0c55e9f6edac57.png)
内部类分为:成员内部类,静态内部类,局部内部类和匿名内部类。
匿名内部类
没有名称的内部类称为匿名内部类。
当某个方法的参数为接口或抽象类对象时,通常会先定义接口的实现类或抽象类的子类,再创建子类对
象作为方法的参数。
如果使用匿名内部类,就可以不用创建子类,而是直接通过匿名内部类作为参数使用。
Lambda表达式
JDK8中的核心升级点。
通常用于简化匿名内部类的写法。
要简化的匿名内部类必须是函数式接口(只有一个抽象方法的接口)。
Lambda表达式语法
(参数类型 参数名) -> {代码语句;}
小括号部分表示参数列表
->部分表示要执行什么
{}部分表示执行的内容
面向过程和面向对象编程思想
面向过程POP:所有步骤按顺序执行,注重执行的细节。
面向对象OOP:创建解决问题的对象,让各个对象调用各自的方法而配合完成。
在面向对象编程OOP中,给类中定义的方法,具体的实现过程,其实也是面向过程的。
对象和类
对象Object
某个类的具体实例
类Class
是拥有相同属性和行为的对象的集合。是对象的模板。
定义类
![](https://i-blog.csdnimg.cn/blog_migrate/66bc794785822e099d849410128694e9.png)
类中的属性
成员变量、局部变量、静态常量
成员变量:定义在类中的变量,即类的属性。它有默认值。通过对象访问。
局部变量:定义在方法中的变量。它没有默认值。只能在方法中赋值后才能使用。
静态常量:特殊的成员变量,用final static修饰。它有默认值。通过类名访问。
类中的方法
构造方法
成员方法
静态方法
![](https://i-blog.csdnimg.cn/blog_migrate/73ddfd631d1594cc1df67affcc591c02.png)
创建对象
![](https://i-blog.csdnimg.cn/blog_migrate/79708bd98f47136ea9c634b50a529428.png)
构造方法
是一种特殊的方法。方法名和类名一致,没有返回值部分。
![](https://i-blog.csdnimg.cn/blog_migrate/747b26109c0e693a0a086c235e3fcfd2.png)
没有返回值部分,方法名必须和类名一致。
在使用new关键字创建对象时,调用对应的构造方法。
每个类在定义后,都隐藏有一个无参的构造方法。
如果自定义了有参数的构造方法,无参数的构造方法就会失效。如果想要使用无参构造方法,就要
再写出来。
构造方法通常用于限制创建对象时携带的参数,初始化成员变量。
构造方法之间都是重载关系,构造方法不能重写。
构造方法执行时,不一定会创建对象。如抽象类中有构造方法,但无法创建抽象类对象,只能在创
建抽象类的子类对象时,自动调用抽象类的构造方法。
面向对象三大特性
封装
将类中的属性使用private修饰,这样就能防止非当前类对其访问,隐藏类中的关键属性。
通常会对private修饰的属性提供公开的get和set方法用于获取和赋值。
继承
类A extend 类B。
接口A extends 接口B。
前者就是后者的子类,前者的对象就能直接访问后者中非私有成员。
重写Override
子类继承父类后,对父类中的非私有方法进行重写,达到拓展或重做的目的
必须满足方法名、返回值、参数列表都相同
访问权限不能比父类中的方法更严格
不能抛出比父类中的方法更大的异常
重载Overload
在一个类中,某个方法在不同的参数下,表现不同的行为。同名不同参。
方法名必须相同
参数列表必须不同(类型和数量)
无返回值无关
this和super
都可以当做对象后构造方法使用。
当做对象:this表示当前类的对象,super当前类的父类对象。
this或super当做对象使用时,只能用在非静态方法中。
当做构造方法
this()表示当前类中无参构造方法,如果带参数就表示对应参数的构造方法
super()表示当前类的父类的无参构造方法,如果带参数就表示对应参数的构造方法
this()或super()只能用在另一个构造方法的首行。
在继承后,如果子类和父类都没有写出任何构造方法时,子类中有一个隐藏的无参构造方法,会自动调
用父类的无参构造方法
![](https://i-blog.csdnimg.cn/blog_migrate/d91d315820b7d9ed89ed3e9c98ba15bc.png)
所以如果在父类中定义了有参数的构造方法,无参构造方法就会失效,子类必须调用父类中的有参数的
构造方法
Object类
是所有类的父类。任何类都间距地继承了Obejct类。所以所有类都能访问Object类中的方法,都可以进
行重写。
toString()是Object类中的一个方法,在输出对象时自动调用。
默认输出"类全限定名@十六进制哈希码"。通常在自定义的实体类中,重写toString(),输出当前类
的属性。
equals()是Object类中的一个方法,用于比较两个对象是否相同。
默认使用==比较内存地址。通常在自定义的实体类中,重写equals(),自定义比较的规则。
hashCode()是Object类中的一个方法,用于获取对象的哈希码。
默认使用全部参数生成哈希码。可以重写自定义生成哈希码的参数。
对象转型
类似于原始类型间的数据类型转换
向上转型:父类变量 = 子类对象;
类似于自动类型转换
![](https://i-blog.csdnimg.cn/blog_migrate/69087c3dabe360a0fc6bd4674b7cc5f4.png)
向下转型: 子类变量 =(子类) 父类对象;
类似于强制类型转换
![](https://i-blog.csdnimg.cn/blog_migrate/4fa2c52bf4b2ea9f17340fe8a025e1b0.png)
多态
在继承关系中,子类的对象可以保存到父类的变量中。(向上转型)
多态常用与定义方法时,形参为一个父类或接口类型变量,实参为子类对象。
无法通过父类变量调用子类中独有的方法。如果调用重写了父类中的方法时,执行重写后的内容
![](https://i-blog.csdnimg.cn/blog_migrate/2ab04bec51aa0b344f9ebd3f7978a871.png)
修饰符
访问修饰符
![](https://i-blog.csdnimg.cn/blog_migrate/9305ae7ec6422395a5b2e42f8e7d3d80.png)
修饰属性
变量变为常量,定义时就要赋值,程序运行过程中不能改变其值。
修饰方法
方法成为最终方法,不能重写。
修饰类
类为最终类,不能被继承。
abstract
修饰方法
方法为抽象方法,没有方法体。同时所在的类也需要使用abstract定义为抽象类
修饰类
抽象类不能创建对象
抽象类除了能定义抽象方法外,其余与普通类无区别
抽象类中可以有构造方法,在创建其子类对象时自动调用
抽象类通常需要被继承,一旦有子类继承,子类就要重写抽象父类中的所有抽象方法,或者子
类也是一个抽象类
interface
用于定义接口的关键字。代替class,能让java实现"多继承"。
如果某个抽象类中的所有方法都是抽象方法时,可以将该类改为接口。
abstract class --> interface
接口是一个完全抽象类,其中的方法都是public abstract修饰的抽象方法,其中的属性都是public
final static修饰的静态常量。
接口中没有构造方法,不能创建对象
接口通过implements“继承”。类A implements 接口A,接口B,称为类A实现了接口A和接口B,一
个类可以"继承"多个父接口
一个类一旦实现了某个接口,就要重写其中的所有抽象方法
JDK1.8后,可以在接口中定义default或static修饰的方法,该方法不用重写。
static
被static修饰的内容称为静态成员
静态成员在类加载时就会保存到内存中,所以访问时通过类名直接访问。
当某个属性或方法被高度重用时,将其定义为静态的,之后通过类名方便调用。
修饰方法
![](https://i-blog.csdnimg.cn/blog_migrate/d88544889a88425443dee57c6a1230ad.png)
修饰属性
![](https://i-blog.csdnimg.cn/blog_migrate/b73b3157aa7c268b201276e12efc5e73.png)
定义代码块
![](https://i-blog.csdnimg.cn/blog_migrate/46cb481d584c14df0355f3fc69e282ca.png)
个人小项目
面向对象综合练习--简易xxx管理
功能:
实现对图书的添加、修改、删除、查询功能
如何保存多个图书?
采用图书数组保存
如何实现添加?
判断数组是否有空元素(元素==null),如果有,将参数对象保存
如何实现删除?
遍历数组,根据参数编号循环比较,如果满足相等,用null覆盖
如何实现查询?
查询所有
遍历数组,空元素无需打印
查询单个
根据编号与数组中的元素遍历比较,满足时返回对应的对象
如何实现修改?
调用查询单个的方法,得到编号对应的对象,使用set方法对某个属性赋值
图书类Book
package test4;
/*
* 图书类
* 编号
* 书名
* 作者
* 类型
* 出版社
* 价格
*
* 定义私有属性
* 自动生成全参构造方法、无参构造方法、getter/setter、toString()
* */
public class Book {
private int id;
//封装属性
private String name;
private String author;
private String type;
private String publisher;
private double price;
//用于输出对象时自动调用
@Override
public String toString() {
return "Book{" +
"id=" + id +
", name='" + name + '\'' +
", author='" + author + '\'' +
", type='" + type + '\'' +
", publisher='" + publisher + '\'' +
", price=" + price +
'}';
}
//封装:getter/setter
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getPublisher() {
return publisher;
}
public void setPublisher(String publisher) {
this.publisher = publisher;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
管理员类Manager
//无参数的构造方法
public Book() {
}
//全部参数的构造方法
public Book(int id, String name, String author, String type, String
publisher, double price) {
this.id = id;
this.name = name;
this.author = author;
this.type = type;
this.publisher = publisher;
this.price = price;
}
}
管理员类Manager
package test4;
/*
* 图书管理员类
* 属性
* 保存图书的容器
*
*
* 方法
* 增 添加图书
* 删 删除图书
* 改 修改图书
* 查 查看图书
*
* */
public class Manager {
//保存图书对象的容器,该属性只能当前类使用,使用private修饰,不提供get/set
private Book[] bookList = new Book[10];
//添加
void addBook(Book book) {
for (int i = 0; i < bookList.length; i++) {
//如果存在空位,将参数保存在该位置上
if (bookList[i] == null) {
bookList[i] = book;
//停止循环,防止装满
break;
}
}
}
//查看所有图书
void showAll() {
System.out.println("编号\t书名");
for (Book book : bookList) {
if (book != null) {
//只显示编号和书名
System.out.println(book.getId()+"\t"+book.getName());
}
}
}
/*
* 根据id修改价格
* */
void update(int id,double newPrice){
//根据id得到对应的图书
//调用当前类中定义的根据id查询Book对象的方法
Book book = getBookById(id);
//判断是否得到
if(book!=null){
book.setPrice(newPrice);
}else{
System.out.println("图书不存在");
}
}
/*
* 根据图书编号删除
* */
void delete(int id) {
//遍历数组
for (int i = 0; i < bookList.length; i++) {
//bookList[i]是数组中的某个book对象
//如果该对象不为空,获取其id与参数判断
if(bookList[i]!=null && bookList[i].getId()==id){
//使用null覆盖,实现删除
bookList[i]=null;
break;
}
}
}
/*
* 根据id得到对应的图书对象
* */
Book getBookById(int id) {
//遍历当前所有的图书对象
for (Book book :bookList) {
//如果遍历出的对象不为空,得到对应的id与参数判断
if (book!=null && book.getId()==id) {
//返回对应的图书
return book;
}
}
//如果遍历未发现满足条件,返回null
return null;
}
}
程序入口类Main
package test4;
import java.util.Random;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
//创建管理员对象
Manager manager = new Manager();
while (true) {
System.out.println("请选择功能:1.添加图书\t2.修改图书\t3.删除图书\t4.查看所
有图书\t5.查看图书详情\t6.退出");
switch (sc.nextInt()) {
case 1:
int id = new Random().nextInt(9000) + 1000;
System.out.println("请输入书名");
String name = sc.next();
System.out.println("请输入作者");
String author = sc.next();
System.out.println("请输入类型");
String type = sc.next();
System.out.println("请输入出版社");
String publisher = sc.next();
System.out.println("请输入价格");
double price = sc.nextDouble();
//创建一个图书对象
Book book = new Book(id, name, author, type, publisher,
price);
//调用添加方法
manager.addBook(book);
break;
case 2:
System.out.println("请输入要修改的编号");
int updateId = sc.nextInt();
System.out.println("请输入要修改的价格");
double newPrice = sc.nextDouble();
manager.update(updateId, newPrice);
break;
case 3:
System.out.println("请输入要删除的编号");
manager.delete(sc.nextInt());
break;
case 4:
manager.showAll();
break;
case 5:
System.out.println("请输入要查看的编号");
System.out.println(manager.getBookById(sc.nextInt()));
break;
case 6:
System.exit(0);
break;
}
面向对象三大特性--继承
概念
类B使用extends(延伸)关键字"继承"类A。
语法:class 类B extends 类A{}
类B称为类A的子类,衍生类,subClass
类A称为类B的父类,超类、supClass
继承后,子类就能访问父类中的非私有(没有使用private修饰)成员变量和成员方法。
将多个类中的公共代码提取出来保存到一个公共类中,这些类使用extends"继承"这一个公共类,从而减
少这些类中的冗余代码。
如猫类、狗类都有类型、昵称等属性,也有吃、睡等方法,那就可以定义一个动物类,将这些公共的属
性和方法定义在动物类这个父类中,
再让猫类和狗类这些子类继承动物类。这样就能直接通过子类访问父类中的内容。
特点
如果多个类之中有相同的代码,可以将这些代码提取出来到一个公共的类中,这个类就是父类。再
让那些类去extends继承这个父类,那些类就是子类。子类就无需再写重复代码
子类中或子类对象可以直接访问父类中非私有(不用private修饰)属性和方法
}
}
}
个人心得
这个阶段的概念知识点比较多,而且也不易理解,所以在学起来比较吃力,要学好这部分要充分理解,面向对象和面向过程,而且要对这部分代码要有足够的熟练度,然后对封装,继承,多态去深刻的理解。对每个项目的每一步都要去用逻辑分析,然后合理的写出每一步