Java SE笔记
Java SE(Java Standard Edition):Java技术的核心和基础
学习视频:https://www.bilibili.com/video/BV1Cv411372m
我参考的笔记:
【Java基础笔记】Java基础学习笔记
Java语言概述
- Java是美国 sun 公司在1995年推出的一门计算机高级编程语言
Java是世界上最流行的编程语言之一,在国内使用最为广泛的编程语言
可移植性、安全可靠、性能较好
开发社区最完善,功能最丰富
我的JDK版本:17.0.1
环境变量配置:
系统变量JAVA_HOME(JAVA_HOME:JDK安装路径)
D:\ XX\ XX\ java\ jdk-17
用户变量Path (Path:告诉操作系统JDK提供的javac编译、java执行命令安装到了哪个位置)
%JAVA_HOME%\bin 或 D:\ XX\ XX\ java\ jdk-17\ bin
- Java开发步骤:
记事本编写:
IntelliJ IDEA编写:
IDEA项目结构介绍:
◾ project(项目、工程)
◾ module(模块)
◾ package(包)
◾ class(类)
package helloworld;
public class hello_1 {
public static void main(String[] args){
System.out.println("helloworld");
}
}
Java语言跨平台原理
一次编译,处处可用
我们的程序只需开发一次,就可以在各种安装了相应的JVM(eg:window版的JVM)的系统平台上运行
Java开发环境(JRE和JDK关系)
API(Application Programming Interface,应用程序编程接口)即核心类库:
Java写好的程序,程序员可以直接调用。Oracle也提供了相应的API文档(技术使用说明书)
JVM(Java Virtual Machine):
Java虚拟机,真正运行Java程序的地方
JRE(Java Runtime Environment):
Java程序的运行环境(包括:JVM+运行时所需的核心类库)
我们想要运行一个已有的Java程序,那么只需安装JRE即可。
JDK(Java Development Kit):
Java程序开发工具包(包括:JRE+开发工具)
我们想要开发一个全新的Java程序,那么必须安装JDK。
开发工具:编译工具(javac.exe)和运行工具(java.exe)
入门基础知识
常用DOS命令
关键字、标识符
- 关键字
Java保留的一些作为特殊功能使用单词,如:public、class、byte、int等
字母全部小写
不能用关键字作为类名或变量名称
常见的代码编辑器,针对关键字有特殊的颜色标记,非常直观。
- 标识符
标识符用于给类、方法、变量等命名
命名要求:
基本要求:数字、字母、下划线、美元符号等组成
强制要求:不能以数字开头、不能是关键字、区分大小写
命名规范:
变量
格式:
数据类型 变量名 = 初始值;
变量使用注意事项:
1.名字不能重复
2.变量未赋值不能使用
3.long类型的变量定义时,为了防止整数过大,后面要加L
4.float类型的变量定义时,为了防止类型不兼容,后面要加r
类型转换
-
数据类型
引用数据类型:String、类、接口、数组
基本数据类型:4大类8种。
整 型:byte 、short、 int(默认)、long
浮点型:float 、double(默认)
字符型:char
布尔型:boolean -
自动类型转换
把一个数据范围小的变量赋值给另一个数据范围大的变量
byte a = 10;
int b = a; // a=10
- 强制类型转换
强行把一个数据范围大的变量赋值给另一个数据范围小的变量
格式:数据类型 变量2 = (数据类型)变量1
int a = 20;
byte b = (byte)a; // b=20
数组(含内存分配)
数组是用来存储一批同种类型数据的内存区域
- 静态初始化数组
定义数组时直接给数组赋值
定义一个数组后,程序执行的过程中,该数组长度和类型无法修改
// 完整格式
数据类型[] 数组名 = new 数据类型[]{元素1,元素2,元素3...};
int[] ages = new int[]{12, 24, 36}
// 简化格式
数据类型[] 数组名 = {元素1,元素2,元素3...};
int[] ages = {12, 24, 36}
- 动态初始化数组
定义数组时只确定元素的类型和数组长度,之后再存入具体数据
数据类型[] 数组名 = new 数据类型[长度];
int[] arr = new int[3];
当前已经知道存入的元素值时用静态初始化。当前还不清楚要存入哪些数据时用动态初始化。
注:“数据类型[] 数组名“也可以写成“数据类型 数组名[]”
在IDEA中,【数组名.fori】快速生成遍历数组语句
- Java内存分配——数组
目录:
一个基本数据类型 int变量 和 一个引用数据类型 数组变量
两个数组变量指向同一个数组对象
数组是引用数据类型,数组变量名中存储的是数组在内存中的地址信息。
内存分为栈、堆、方法区、本地方法栈、寄存器五个区
实际上只需要重点关注栈、堆、方法区这三个区,如下图:
- 一个基本数据类型 int变量 和 一个引用数据类型 数组变量
在栈内存中,基本数据类型存的是数据,引用数据类型(如:数组)存的是地址。
- 两个数组变量指向同一个数组对象
方法(含内存分配)
方式是一种语法结构,可以把一段代码封装成一个功能,以方便重复调用
/**
* 修饰符 返回值类型 方法名( 形参列表 ) {
* 方法体代码(需要执行的功能代码)
* return 返回值;
* }
*/
public class DemoHello {
public static void main(String[] args) {
getnum(5);
}
public static int getnum(int num){
System.out.println(num);
return 0;
}
}
- 方法重载
同一个类中,出现多个方法名称相同,但是形参列表是不同的,那么这些方法就是重载方法。
调用方法的时候,会通过参数的不同来区分调用的是哪个方法
public static void fire(){}//调用fire()
public static void fire(String location){}//调用fire("中国")
可读性好,方法名称相同提示是同一类型的功能,通过形参不同实现功能差异化的选择,这是一种专业的代码设计。
- Java内存分配——方法调用
目录:
一个方法调用
多个方法调用
结合上面数组的内存分配知识理解下面的知识
方法的运行区域在栈内存-
一个方法调用
执行到main函数的第一行代码时要暂停一下,把add函数放入栈内存中
add函数执行完毕,把值返回给sum后,add函数就从栈内存退出去了
接着执行main函数第二行代码
main函数执行完毕后,也退出栈内存
-
多个方法调用
-
public class method {
public static void main(String[] args) {
study();
}
public static void sleep() {
System.out.println("睡觉");
}
public static void eat() {
System.out.println("吃饭");
}
public static void study() {
eat();
System.out.println("学习");
sleep();
}
}
常用API
键盘录入、随机数
- 键盘录入
- 以键盘录入技术为案例,使用到Scanner类
import java.util.Scanner;
public class DemoHello {
public static void main(String[] args){
/**
* nextInt():输入一个int型数字
* next():输入一个字符串(空格将作为分隔符),返回String类型
* nextLine():输入一行(包含空格),返回String类型
*/
Scanner sc = new Scanner(System.in); // 获取键盘扫描器对象
System.out.println("请输入您的年龄:");
int age = sc.nextInt(); // 获取用户int型输入数据
System.out.println("您的年龄是:" + age);
System.out.println("请输入您的名称:");
String name = sc.next();
System.out.println("您的名称:" + name);
}
}
请输入您的年龄:
18
您的年龄是:18
请输入您的名称:
谢 谢谢
您的名称:谢
- 随机数
- 以随机数技术为案例,使用到Random类
//生成随机数
import java.util.Random;
public class DemoHello {
public static void main(String[] args) {
/**
* nextInt(n):生成 0 ~ (n-1) 之间的随机数
* 即要生成 m ~ m+(n-1)之间的随机数: nextInt(n) + m
*/
Random r=new Random();
System.out.println("随机生成5~12之间的数:");
int data = r.nextInt(8) + 5; // r.nextInt(8)生成随机数0-7
System.out.print(data + "\t");
}
}
//猜数字游戏
import java.util.Scanner;
import java.util.Random;
public class DemoHello {
public static void main(String[] args) {
Random r=new Random();
int num_aim= r.nextInt(101);//0~100
Scanner sc=new Scanner(System.in);
while (true){
System.out.println("请输入您在0-100中猜测的数字:");
int num_guess= sc.nextInt();
if(num_guess==num_aim){
System.out.println("猜对了");
break;
}
if(num_guess<num_aim)
System.out.println("小了");
if(num_guess>num_aim)
System.out.println("大了");
}
}
}
字符串类型String类(含内存分配)
目录:
String类 概述
String类 创建对象
String类 常见面试题
String类 常用API
- String类概述
java.lang.String类代表字符串,String类定义的变量可以用于指向字符串对象,然后操作该字符串
Java程序中的所有字符串文字(eg:“abc”)都是String类的对象
String类的特点
常被称为不可变字符串类型,它的对象在创建后不能被更改
从内存分配角度解释字符串对象的存储位置:
以" "方式给出的字符串对象,在字符串常量池中存储
因此String是不可变字符串的原因:
String变量每次的修改其实都是产生并指向了新的字符串对象
旧的字符串对象是没有改变的
- String类创建对象
String类创建对象有两种方式:
方式一:直接使用“ ”定义(推荐方式)
String str = "Java";
方式二:通过String类的构造器创建对象
注:两种创建方式的区别(面试常考)
以 " " 方式给出的字符串对象,在字符串常量池中存储,而且相同内容只会在常量池中存储一份
通过构造器new对象,每new一次都会产生一个新对象,放在堆内存中
- String类常见面试题
面试题一:
问题:下列代码的运行结果是?
public class HelloWorld {
public static void main(String []args) {
String s1 = new String("abc");
String s2 = "abc";
System.out.println(s1 == s2);
}
}
此时string si=“abc”;创建了0个对象,因为abc已经在常量池里了
面试题二:
问题:下列代码的运行结果是?
- String类常用API
- String类常用API——字符串内容比较
此时“==”比较的是地址,而sysLoginName在常量池,LoginName在堆内存中
因此使用String类提供的equals()方法比较: 只比较内容是否一致(不在意地址)
- String类常用API——遍历、替换、截取、分割
集合ArrayList类
目录:
ArrayList类 概述
ArrayList类 创建
ArrayList类 常用API
-
ArrayList类 概述
集合是与数组类似,也是一种容器,用于装数据的。
数组的特点:数组定义完成并启动后,类型确定、长度固定。
问题:在个数不能确定,且要进行增删数据操作的时候,数组是不太合适的。
集合的特点:
1.集合的大小不固定,启动后可以动态变化,类型也可以选择不固定。
2.集合非常适合做元素个数不确定且,要进行增删操作的业务场景。
3.集合还提供了许多丰富、好用的功能,而数组的功能很单一。 -
ArrayList类 创建
ArrayList是集合的一种,它支持索引。
ArrayList list = new ArrayList();
list.add("Java");
ArrayList对泛型的支持
ArrayList其实就是一个泛型类,可以在编译阶段约束集合对象只能操作某种数据类型。
/**
* eg:ArrayList<String>:此集合只能操作字符串类型的元素。
* ArrayList<Integer>:此集合只能操作整数类型的元素。
* 注意:集合中只能存储引用类型,不支持基本数据类型。
*/
ArrayList<String> list1 = new ArrayList<>();
统一ArrayList集合操作的元素类型
- ArrayList类 常用API
实例:
public static void main(String[] args) {
ArrayList<Integer> scoreList = new ArrayList<>();
scoreList.add(90);
scoreList.add(80);
scoreList.add(70);
scoreList.add(60);
scoreList.add(50);
System.out.println("班级成绩:" + scoreList);
// 一边遍历一遍删除时,要从后往前遍历,否则会漏数据
for (int i = scoreList.size() - 1; i > 0; i--) {
if (scoreList.get(i) < 80) {
scoreList.remove(i);
}
}
System.out.println("高于80分的成绩:" + scoreList);
}
班级成绩:[90, 80, 70, 60, 50]
高于80分的成绩:[90]
面向对象基础
面向对象的三大特点:封装、继承、多态
面向对象并不是一个技术,而是一种编程指导思想。
把现实世界的具体事物全部看成一个一个的对象来解决问题。按照面向对象编程来设计程序:程序代码符合人类思维习惯,更易理解、更简单
1.类和对象(含内存分配)
目录:
1.1 设计对象并使用
1.2 Java内存分配——对象
1.3 垃圾回收
- 1.1 设计对象并使用
在Java中,必须先定义类,才能创建对象。
类:类是一个模板,它描述一类对象的共同特征(如行为和状态)。
对象:是类的一个具体实例。
简单理解:类是对相同事物的共同特征的描述,对象则为具体存在的实例。
//定义类
public class 类名 {
1、成员变量(代表属性的,一般是名词)
2、成员方法(代表行为的,一般是动词)
}
//获得类的对象
类名 对象名 = new 类名();//类名首字母建议大写,满足“驼峰模式”
//访问类的成员的格式
对象名.成员变量
对象名.成员方法();
类中成分:
五大成分:成员变量,成员方法、构造器、代码块、内部类
public class Student {
//1.成员变量:描述类或者对象的属性信息//一般无需指定初始化值,存在默认值。
private String name;
//2.构造器:始化一个类的对象并返回对象的地址
public Student() { }
//3.成员方法:描述类或者对象的行为
public void run() { }
//4.代码块
static { }
//5.内部类
public class Girl{ }
}
注意:一个Java文件中可以定义多个类,打算只能有一个类是public修饰的,
public修饰的类名必须成为Java代码文件名。
实际开发中建议还是一个文件定义一个class类。
public class Student {}
class Teacher {}
- 1.2 Java内存分配——对象
目录:
1.2.1 两个对象的内存分配
1.2.2 两个变量指向同一个对象的内存分配
1.2.3 补充:成员变量和局部变量的区别
- 1.2.1 两个对象的内存分配
以下列代码为例:
此时执行Car c1=new Car();
在堆内存中分配一块区域,即为对象。接着在对象中分配成员变量(此时为默认值,如int变量默认值为0)
注意成员方法并没有放在这里(因为方法有可能代码内容很多,不可能全放在堆内存中,会浪费内存,所以直接放在方法区),而是存放成员方法的引用地址。
栈内存中c1里面存放的是对象在堆内存中的的地址。如下图:
执行接下来四行代码
给对象里面的成员变量赋值
执行接下来两行代码:从栈内存c1找到堆内存中的对象,再由引用地址找到方法区中的成员方法
输出结果
同理,c2
最后,你可以验证一下
System.out.println(arr1);
System.out.println(c1);
和数组一样,栈内存中c1存放的是对象在堆内存中的地址
- 1.2.2 两个变量指向同一个对象的内存分配
- 1.2.3 补充:成员变量和局部变量的区别
- 1.3 垃圾回收
当堆内存中的类对象或数组对象,没有被任何变量引用(指向)时,就会被判定为内存中的“垃圾”
Java存在自动垃圾回收器,会定期进行清理
2.构造器、this关键字
- 2.1 构造器
用于初始化一个类的对象,并返回对象的地址
初始化对象的格式——类型 变量名称 = new 构造器;
构造器的分类:无参数构造器(默认存在): 初始化对象时,成员变量的数据均采用默认值
有参数构造器: 在初始化对象时,同时可以为对象进行赋值
- 2.2 this关键字
出现在成员方法、构造器中,代表当前对象的地址,用于访问当前对象的成员变量、成员方法
public class Student {
private String name;
public void setName(String name) {
this.name = name;
}
}
3.封装、标准JavaBean
面向对象的三大特点:封装、继承、多态
- 3.1 封装
隐藏实现细节,暴露出合适的访问方式(合理隐藏、合理暴露)
封装的实现步骤:
一般对成员变量使用private(私有)关键字修饰进行隐藏,private修饰后该成员变量就只能在当前类中访问
提供public修饰的getter、setter方法暴露其取值和赋值
public class Student {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
通常将 成员变量私有、提供成员方法进行暴露。
- 3.2 标准JavaBean
可以理解成实体类,其对象可以用于在程序中封装数据
标准JavaBean的要求:
成员变量使用private修饰
提供每一个成员变量对应的getter和setter方法
必须提供一个无参构造器
4.静态关键字static
目录:
4.1 static修饰成员变量
4.2 static修饰成员方法
4.3 static实际应用
static是静态的意思,
可以修饰成员变量,表示该成员变量在内存中只存储一份,可以被共享访问、修改。
- 4.1 static修饰成员变量(含内存分配)
static修饰成员变量时的内存分配:
前四行代码:
先分配静态成员变量的内存
此时不分配实例成员变量的内存,因为实例成员变量属于对象,而现在没有对象
- 4.2 static修饰成员方法
static修饰成员方法的内存原理:
因为getMax()是属于类的,所以入口一开始就暴露在方法区里
- 4.3 static的应用
对于一些应用程序中多次需要用到的功能,可以讲这些功能封装成静态方法,放在一个类中,这个类就是工具类
作用:一次编写,处处可用。
将工具类的构造器私有,不让工具类对外产生对象。
为什么工具类中的方法不用实例方法做?
因为实例方法需要创建对象调用,此时用对象只是为了调用方法,这样只会浪费内存。
未完待续、、、、、
5.继承
目录:
5.1 概述
5.2 继承的内存原理
5.3 继承后:成员变量、成员方法的访问特点
5.4 继承后:方法重写
5.5 继承后:子类构造器
5.6 this 和 super 关键字使用总结
面向对象的三大特征:封装、继承、多态
- 5.1 概述
子类继承父类,子类可以得到父类的属性和行为,子类可以使用
格式:
class 父类 {}
class 子类 extends 父类 {}
继承的特点:
子类可以继承父类的属性和行为,但子类不能继承父类的构造器
子类有自己的构造器,父类构造器用于初始化父类对象
子类可以继承父类的私有成员,但不能直接访问
子类可以直接使用父类的静态成员(共享并非继承)
Java是单继承模式:一个类只能继承一个直接父类
Java不支持多继承,但支持多层继承
Java中所有类都是Object类的子类(Object是祖宗类)
- 5.2 继承的内存原理:
一个对象在堆内存中划出的一块空间,这块空间分两部分,一个父类空间一个子类空间
- 5.3 继承后:成员变量、成员方法的访问特点
- 就近原则:
先在子类局部范围找
然后在子类成员范围找
最后在父类成员范围找,如果父类范围没有找到则报错
上图结果是“子类动物”
如果子父类中,出现了重名的成员,会优先使用子类中的。可以通过super关键字,指定访问父类的成员
- 5.4 继承后:方法重写
在继承体系中,子类出现了和父类中一模一样的方法声明,子类中的这个方法就是重写方法
应用场景:当子类需要父类的功能,但父类的这个功能不完全满足子类的需求时,子类可以重写父类中的方法
-
5.5 继承后:子类构造器
-
5.5.1 子类构造器的特点
实例:子类构造器访问父类无参构造器
public class Animal {
public Animal() {
System.out.println("==父类Animal无参构造器执行==");
}
}
public class Cat extends Animal {
public Cat() {
// super(); 不写也存在
System.out.println("==子类Cat无参构造器执行==");
}
public Cat(String name) {
// super(); 不写也存在
System.out.println("==子类Cat有参构造器执行==");
}
}
public class Test {
public static void main(String[] args) {
Cat cat1 = new Cat();
System.out.println("----------");
Cat cat2 = new Cat("Kitty");
}
}
结果:
==父类Animal无参构造器执行==
==子类Cat无参构造器执行==
----------------------------------------
==父类Animal无参构造器执行==
==子类Cat有参构造器执行==
- 5.5.2 继承后:子类构造器访问父类有参构造器
public class Animal {
public Animal() {
System.out.println("==父类Animal无参构造器执行==");
}
public Animal(String name) {
System.out.println("==父类Animal有参构造器执行==");
}
}
public class Cat extends Animal {
public Cat(String name) {
super(name);
System.out.println("==子类Cat有参构造器执行==");
}
}
public class Test {
public static void main(String[] args) {
Cat cat2 = new Cat("猫");
}
}
结果:
==父类Animal有参构造器执行==
==子类Cat有参构造器执行==
- 5.6 this 和 super 关键字使用总结
6.包、权限修饰符
- 6.1 包
- 6.2 权限修饰符
如果该成员只希望本类访问,使用private修饰
如果该成员只希望本类同一个包下的其他类和子类访问,使用protected修饰
7.final关键字、常量、枚举
- 7.1 final关键字
- 7.2 常量
7.2.1 实例:
import javax.swing.*;
import java.awt.event.ActionEvent;
public class ConstantDemo {
public static final int UP = 1; // 上
public static final int DOWN = 2; // 下
public static final int LEFT = 3; // 左
public static final int RIGHT = 4; // 右
public static void main(String[] args) {
// 创建一个窗口对象
JFrame window = new JFrame();
// 创建一个面板对象,并添加给窗口
JPanel panel = new JPanel();
window.add(panel);
// 创建4个按钮对象
JButton btnUp = new JButton("上");
JButton btnDown = new JButton("下");
JButton btnLeft = new JButton("左");
JButton btnRight = new JButton("右");
// 将按钮添加到面板上
panel.add(btnUp);
panel.add(btnDown);
panel.add(btnLeft);
panel.add(btnRight);
// 显示窗口
window.setLocationRelativeTo(null);
window.setSize(300, 100);
window.setVisible(true);
// 给每个按钮添加监听
btnUp.addActionListener(new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
move(UP);
}
});
btnDown.addActionListener(new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
move(DOWN);
}
});
btnLeft.addActionListener(new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
move(LEFT);
}
});
btnRight.addActionListener(new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
move(RIGHT);
}
});
}
public static void move(int action) {
switch (action) {
case UP:
System.out.println("上");
break;
case DOWN:
System.out.println("下");
break;
case LEFT:
System.out.println("左");
break;
case RIGHT:
System.out.println("右");
break;
}
}
}
- 7.3 枚举
7.3.1 实例:
//做信息标志和分类
public enum Orientation {
UP,DOWN,LEFT,RIGHT;
}
import javax.swing.*;
import java.awt.event.ActionEvent;
public class ConstantDemo {
public static final int UP = 1; // 上
public static final int DOWN = 2; // 下
public static final int LEFT = 3; // 左
public static final int RIGHT = 4; // 右
public static void main(String[] args) {
// 创建一个窗口对象
JFrame window = new JFrame();
// 创建一个面板对象,并添加给窗口
JPanel panel = new JPanel();
window.add(panel);
// 创建4个按钮对象
JButton btnUp = new JButton("上");
JButton btnDown = new JButton("下");
JButton btnLeft = new JButton("左");
JButton btnRight = new JButton("右");
// 将按钮添加到面板上
panel.add(btnUp);
panel.add(btnDown);
panel.add(btnLeft);
panel.add(btnRight);
// 显示窗口
window.setLocationRelativeTo(null);
window.setSize(300, 100);
window.setVisible(true);
// 给每个按钮添加监听
btnUp.addActionListener(new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
move(Orientation.UP);//用常量时随便输入什么都可以,枚举直接限制了
}
});
btnDown.addActionListener(new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
move(Orientation.DOWN);
}
});
btnLeft.addActionListener(new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
move(Orientation.LEFT);
}
});
btnRight.addActionListener(new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
move(Orientation.RIGHT);
}
});
}
public static void move(Orientation orient) {
switch (orient) {
case UP:
System.out.println("上");
break;
case DOWN:
System.out.println("下");
break;
case LEFT:
System.out.println("左");
break;
case RIGHT:
System.out.println("右");
break;
}
}
}
8.抽象类
- 8.1 抽象类
public abstract class Animal {
public abstract void run();
}
public class Cat extends Animal {
@Override
public void run() {//必须要这个方法,不然报错
System.out.println("抽象类");
}
}
8.1.1 实例:
public abstract class Card {
private String name;
private double totalmoney;
public abstract void pay(double money);
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double gettotalmoney() {
return totalmoney;
}
public void settotalmoney(double totalmoney) {
this.totalmoney = totalmoney;
}
}
public class GoldCard extends Card {
@Override
public void pay(double money) {
money *= 0.8;
double totalmoney = gettotalmoney() - money;
System.out.println(getName() + "当前账户总金额:" + gettotalmoney() + ",当前消费了:" + money + ",消费后的余额为" + totalmoney);
setBalance(totalmoney);
}
}
public class CardTest {
public static void main(String[] args) {
GoldCard goldCard = new GoldCard();
goldCard.setBalance(10000);
goldCard.setName("李明");
goldCard.pay(800);
}
}
李明当前账户总金额:10000.0,当前消费了:640.0,消费后的余额为9360.0
8.1.2 补充:final和abstract的关系
互斥关系
abstract定义的抽象类作为模板让子类继承,final定义的类不能被继承
抽象方法定义通用功能让子类重写,final定义的方法子类不能重写
8.1.3 抽象类的应用:模板方法模式
public abstract class Account {
private static final String LOGIN_NAME = "admin";
private static final String PASSWORD = "123456";
private String cardId;
private double money;
public Account(String cardId, double money) {
this.cardId = cardId;
this.money = money;
}
/**
* 模板方法添加final,避免被子类重写
* @param loginName 登录名
* @param password 密码
*/
public final void handle(String loginName, String password) {
if (loginName.equals(LOGIN_NAME) && password.equals(PASSWORD)) {
//System.out.println("登录成功!");
double result = calc();
System.out.println("本账户利息是:" + result);
} else {
System.out.println("用户名或密码不正确!");
}
}
public abstract double calc();
public String getCardId() {
return cardId;
}
public void setCardId(String cardId) {
this.cardId = cardId;
}
public double getMoney() {
return money;
}
public void setMoney(double money) {
this.money = money;
}
}
public class CurrentAccount extends Account {
private static final double CURRENT_RATE = 0.0035;
public CurrentAccount(String cardId, double money) {
super(cardId, money);
}
@Override
public double calc() {
return getMoney() * CURRENT_RATE;
}
}
public class Test {
public static void main(String[] args) {
CurrentAccount currentAccount = new CurrentAccount("ICBC-01",100000);
currentAccount.handle("admin","123456");
}
}
9.接口
目录:
9.1 概述
9.2 接口的基本使用:被实现
9.3 接口与接口的关系:多继承
9.4 JDK8开始接口新增方法
9.5 使用接口的注意事项
- 9.1 概述
接口就是体现规范的,其中用抽象方法定义的一组行为规范,接口是更加彻底的抽象
(eg:鼠标、键盘、充电器等都必须满足USB接口规范)
public interface demoInterface {
// 常量(public static final可以省略不写,接口会默认加上)
//public static final String NAME = "李明";
String NAME = "李明";
// 抽象方法(public abstract可以省略不写,接口会默认加上)
//public abstract void run();
void run();
}
接口不能创建对象。
eg:demoInterface inter=new demoInterface()会报错
- 9.2 接口的基本使用:被实现
类和接口的关系: 多实现
public interface People {
void run();
}
public class PingPongMan implements People{
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public void run() {
System.out.println("跑步");
}
}
public class Test{
public static void main(String[] args) {
PingPongMan man=new PingPongMan();
man.run();
}
}
- 9.3 接口与接口的关系:多继承
//接口和接口的关系: 多继承,一个接口可以同时继承多个接口
public interface SportsMan extends People,Sports {}
public class BasketballMan implements SportsMan {}
- 9.4 JDK8开始接口新增方法
public interface People {
void run();
//第一种:默认方法
//接口不能创建对象,这个方法只能过继给实现类,由实现类对象调用
default void sport(){
System.out.println("sport");
}
//第二张:
//必须接口名自己调用
static void inAddr(){
System.out.println("inAddr");
}
//第三种:私有方法
//必须在接口内部才被访问
private void go(){
System.out.println("go");
}
default void run1(){
go();
}
}
public class PingPongMan implements People{
private String name;
@Override
public void run() {
System.out.println("跑步");
}
}
public class Test{
public static void main(String[] args) {
PingPongMan man=new PingPongMan();
man.run();
man.sport();
People.inAddr();//接口名
man.run1();
}
}
//结果:
跑步
sport
inAddr
go
新增的三种方法很少在开发中使用,通常是Java源码中涉及到。
- 9.5 使用接口的注意事项
◾ 接口不能创建对象
◾ 一个类实现多个接口,多个接口中有同样的静态方法,不冲突(因为接口中的静态方法由接口名.方法调用)
◾ 一个类继承了父类,同时又实现了接口,父类中和接口中有同样的方法,默认用父类的
◾ 一个类实现了多个接口,多个接口中存在同样的默认方法,不冲突,这个类重写该方法即可
◾ 一个接口继承多个接口,是没有问题的,如果多个接口中存在规范冲突(同名但不同返回类型的抽象方法)则不能多继承
10.多态
目录:
10.1 概述
10.2 多态的优势
10.3 多态下引用数据类型的转换
10.4 多态的案例
-
10.1 概述
-
10.2 多态的优势
-
10.3 多态下引用数据类型的转换
强制类型转换可以转换成真正的的子类类型,从而调用子类的独有功能
- 10.4 多态的案例
public interface USB {
void input();
void ouput();
void function();
}
public class Mouse implements USB{
private String name;
public Mouse(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public void input() {
System.out.println("成功接入"+getName());
}
@Override
public void ouput() {
System.out.println("成功拔出"+getName());
}
@Override
public void function() {
System.out.println("完成"+getName()+"的点击功能");
}
}
public class Keyboard implements USB{
private String name;
public Keyboard(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public void input() {
System.out.println("成功接入"+getName());
}
@Override
public void ouput() {
System.out.println("成功拔出"+getName());
}
@Override
public void function() {
System.out.println("完成"+getName()+"的打字功能");
}
}
public class Computer {
private String name;
public Computer(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void installUSB(USB usb){
if (usb instanceof Mouse){
Mouse mouse=(Mouse) usb;
System.out.println("install "+mouse.getName());
mouse.input();
mouse.function();
mouse.ouput();
}else if (usb instanceof Keyboard){
Keyboard keyboard=(Keyboard) usb;
System.out.println("install "+keyboard.getName());
keyboard.input();
keyboard.function();
keyboard.ouput();
}
}
}
public class Test{
public static void main(String[] args) {
Computer computer=new Computer("DELL");
computer.installUSB(new Mouse("鼠标"));
System.out.println("---------------");
computer.installUSB(new Keyboard("键盘"));
}
}
install 鼠标
成功接入鼠标
完成鼠标的点击功能
成功拔出鼠标
---------------
install 键盘
成功接入键盘
完成键盘的打字功能
成功拔出键盘
Process finished with exit code 0