无论多么艰难,都要继续前进,因为只有你放弃的那一刻,你才输了。
一、学前预备知识
1.常见cmd命令
1.盘符名称+冒号
- 说明:盘符切换
- 举例:E: 回车,表示切换到E盘
- 2.dir
- 说明:查看当前路径下的内容(包括隐藏内容)
- 3.cd目录
- 说明:进入单级目录
- 举例:cd 爱奇艺
- 4.cd..
- 说明:回退到上一级
- 5.cd 目录1\目录2\...
- 说明:进入多级目录
- 举例:cd 爱奇艺\电视剧
- 6.cd \
- 说明:回退到盘符目录
- 7.cls
- 说明:清屏
- 8.exit
- 说明:退出命令提示符窗口。
2.软件下载即配置
1.JDK目录
要着重bin目录
2.环境配置
JDK所配置的环境,仅包含了四个工具,所以要自己进行配置
1.先删掉jdk配置的环境
2.先配置JAVA_HOME。(路径不带bin)
3.再配置Path.(%IAVA_HOME%\bin)
二、基础
1.基础知识
JAVA SE JAVA语言的标准版,用于桌面应用的开发,是其他两个版本的基础。
JAVA ME java语言的小型版,用于嵌入式电子设备或者小型一定设备,现在不常用。
JAVA EE java语言的企业版,用于Web方向的网站开发。网站开发:浏览器+服务器
JAVA的主要特性:
1.面向对象 2.跨平台 3.开源 4.简单易用 5.多线程 6.安全性
java是混合型的编译运行方式
JAVA语言的跨平台是通过虚拟机实现的。
JAVA语言不是直接运行在操作系统里边的。而是运行在虚拟机中的。
针对不同的操作系统,安装不同的虚拟机就可以。
JDK(java development kit):java开发工具包 包括:
- JVM(java virtual machine):java虚拟机,真正运行JAVA程序的地方
- 核心类库:java已经写好的东西,我们可以直接用
- 开发工具 javac 编译工具 java运行工具 jdb 调试工具….
JRE(java runtime environment):JAVA的运行环境
- JVM(java virtual machine):java虚拟机,真正运行JAVA程序的地方
- 核心类库:java已经定义好的库
- 运行工具
2.基础概念
1.注释:
idea中的快捷键是ctrl+shift+/
- 单行注释 //
- 多行注释 /**/
- 文档注释
注释使用细节:
- 注释内容不会参与编译和运行,仅仅是对代码的解释说明
- 不管是单行注释还是多行注释,在书写的时候都不要嵌套
2.关键字:被JAVA赋予了特定涵义的英文单词
关键字特点:
- 关键字的字母全部小写
- 常用的代码编辑器,针对关键字有特殊颜色标记
class:用于创建/定义一个类,后面跟随类名
3.字面量:数据在程序中的书写格式
分类:
字面量类型 | 说明 | 举例 |
整数类型 | 不带小数点的数字 | 666,-88 |
小数类型 | 带小数点的数字 | 13.14 -13.12 |
字符串类型 | 用双引号括起来的内容 | “Hello World”,"程序" |
字符类型 | 用单引号括起来的内容,内容只能有一个 | 'A','0','我' |
布尔类型 | 布尔值,表示真假 | 只有两个值:true,false |
空类型 | 一个特殊的值,空值 | NULL“NULL”不能直接打印,只能以字符串的形式打印 |
特殊字符:
\t 制表符 在打印的时候,把前面字符串的长度补齐到8,或者8的整数倍。最少补1个空格,最多补8个空格。(可以让打印的数据对齐)
4.变量:在程序执行过程中,值可能会发生改变的量
变量的定义格式
数据类型 变量名=数据值;
变量的注意事项:
1.只能存一个值
2.变量名不允许重复定义
3.一条语句可以定义多个变量
4.变量在使用之前一定要进行赋值
5.变量的作用域范围
5.计算机的存储规则
1.txt文本--数字 转二进制存储--字母、汉字 查询码表
2.Image图片--每一个像素点的RGB三原色来存储
3.Sound声音--对声音的波形图进行采样再存储
6. 数据类型
1.基本数据类型
- 如果要定义long类型的变量 在数据值的后面需要加一个L作为后缀,L可以是大写也可以是小写,推荐大写。
long n=99999L;
- 如果要定义float类型的变量 在数据值的后面需要加一个F作为后缀,F可以是大写也可以是小写,推荐大写。
float f=10.1f;
- double类型不用加后缀。
- 布尔类型:
-
boolean o=true;
- 整数和小数取值范围大小关系:
double>float>long>int>short>byte
2.引用数据类型
标识符:给类、方法、变量等起的名字
标识符命名规则--硬性要求
由数字、字母、下划线(_)和美元符($)组成
3.IDEA下载使用
IDEA项目结构介绍
1.project 项目
2.module 模块
3.package 包
4.class 类
Eg:
微信看做 项目
下方 消息、通讯录、发现、我 可以看做四个独立的模块
以消息为例:
IDEA中的代码:
缩写:
psvm:
public static void main(String [] args){
}
sout:
System.out.println();
输出语句:
System.out.println("abc");//先打印abc再进行换行
System.out.print("abc");//只打印abc,不换行
System.out.println();//不打印任何数据,只做换行处理
System.out.printf("%s你好","张三");//用后边的字符串来填补%s,不能自动换行,输出:张三你好
System.out.printf("%s你好%s","张三","李四");//输出张三你好李四
关于类的操作:
1.删除类:右键,delete
2.新创建类
3.修改类名:右键,refector,rename
关于模块:
1.新建
2.删除
3.修改
4.导入
三、语法
1.运算符
算术运算符
+ - * / %
- 有小数参与运算时,结果有可能不精确
- 整数参与运算,结果只能是整数
- 想要得到小数,要有小数参与运算
高级用法
- 数字相加
数据类型不一致,需要转成一致的才能参与运算
类型转换的分类
1.隐式转换--(自动的)
- 取值范围小的转换成取值范围大的
- Byte、short、char三种类型的数据在运算时,都会直接先提升为int,然后再进行运算
2.强制转换
- 把取值范围大的数值,赋值给取值范围小的数值
- 格式: 目标数据类型 变量名=(目标数据类型)被强转的数据;
- 字符串的“+”操作
- 当“+”操作中出现字符串时,,这个“+”是字符串连接符,而不是算术运算符了。会将前后的数据进行拼接,并产生一个新的字符串
- 连续进行“+”操作时,从左到右逐个执行
- 字符相加
- 字符+字符或者是字符+数字时,会把字符通过ASCLL码表查询到对应的数字再进行计算。
自增自减运算符
- ++、--
- ++ 、--无论放在变量前边还是放在后边,单独放一行,结果一样。
- A++ ,先用后加 ++a, 先加后用
赋值运算符
- = 赋值
- += 加后赋值 a+=b,将a+b的值给a
- -= 减后赋值 a-=b,将a-b的值给a
- *= 乘后赋值 a*=b,将a*b的值给a
- /= 除后赋值 a/=b,将a/b的商给a
- %= 取余后赋值 a%=b,将a/b的余数给a
- += -= *= /= %=底层都隐藏了一个强制类型转换
关系运算符
- 关系运算符的结果都是boolean类型
import java.util.Scanner;
public class base {
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
int me=sc.nextInt();
int girl=sc.nextInt();
boolean result=me>girl;
System.out.println(result);
}
}
逻辑运算符
- & 逻辑与(且)---两边都满足
- | 逻辑或 ----两边满足一个
- ^ 逻辑异或-----同为false,不同为true
- !逻辑非-----取反
短路逻辑运算符
- && 短路与---结果与单个&一样,但是具有短路效果,当左边的表达式的值可以确定最终的结果,右边就不会参与运算。
- || 短路或-----结果与|一样,但是具有短路效果,当左边的表达式的值可以确定最终的结果,右边就不会参与运算。
- 注意事项:
- & |,无论左边true false,右边都要执行。
- && ||,如果左边能确定整个表达式的结果,右边不执行。
- &&:左边为false ,右边不管是真是假,整个表达式的结果一定是false。
- ||:左边为true,右边不管是真是假,整个表达式的结果一定是true。
- 这两种情况,右边不执行,提高了效率。
三元运算符:可以进行判断,根据判断的内容来选择不同的结果
- 格式:关系表达式? 表达式1:表达式2;
- 如果关系表达式的值为真,则输出表达式1的值,否则输出表达式2的值。
- 三元运算符的值必须要使用。
运算符优先级
- ()最高
2.判断和循环
流程控制语句
- 顺序结构
-
判断语句
-
If 格式:
- 第一种格式
-
if(关系表达式){
语句体;
}
注意点:
1.大括号的开头可以另起一行书写,但最规范的是写在第一行的末尾
2.在语句体中,如果只有一句代码,大括号可以不写
3.如果对一个布尔类型的变量进行判断,可以不用写==
- 第二种格式:
if(关系表达式){
语句体;
}
else{
语句体2;
}
- 第三种格式:
if(关系表达式1){ 语句体; } else if(关系表达式2){ 语句体2; } else{ 语句体n; }
-
Switch
switch(表达式){ case 1: 语句体1; break; case 2: 语句体2; break; ... default: 语句体n; break; }
- default的位置和省略
- default可以省略,语法不会有问题,但是不建议省略
- default可以写在任何位置,但是习惯写在最下边
- Case 穿透---语句体当中没有写break;
- 执行后没有遇到break,就不会结束整个switch,会继续往下穿透,直到遇到break或者是大括号
- switch的新特性
- Jdk12后才有
- default的位置和省略
switch(表达式){
case 1->{
//语句体1;
}
case 2->{
//语句2;
}
...
default->{
语句3;
}
}
- 当每个case语句 中只用执行一句话时可以用:
switch(表达式){
case 1-> System.out.println("1");
case 2-> System.out.println("2");
...
default-> System.out.println("3");
}
-
再结合case的穿透性
switch(表达式){
case 1,2-> System.out.println("2");
...
default-> System.out.println("3");
}
-
循环语句
- for
- 格式:
- for
for(初始化语句;条件判断语句;条件控制语句){
循环体语句;
}
-
while
- 格式
初始化语句;
while(条件判断语句){
循环体语句;
条件控制语句;
}
- for和while的区别
- for循环中,控制循环的变量,因为归属for循环的语法结构中,在for循环结束后,就不能再次被访问到了。
- while循环中,控制循环的变量,对于while循环来说不归属其语法结构中,在while循环结束后,改变量还可以继续使用。
-
do ...while
- 格式
初始化语句;
do{
循环体语句;
条件控制语句;
}while(条件判断语句);
- 无限循环
- 格式
do{
语句体
}while(true);
for(;;){
语句体
}
while(true){
语句体
}
- 跳转控制语句
- Continue 结束本次循环,继续下次循环
- Break 结束整个循环
3.数组
数组指的是一种容器,可以用来存储同种数据类型的多个值
数组容器在存储数据的时候,需要结合隐式转换考虑
数组的定义
格式1:
数据类型[] 数组名
int [] array;
格式2:
数据类型 数组名[]
int array2[];
数组的初始化
- 静态初始化
格式:
完整格式:
数据类型 [] 数组名= new 数据类型[] {};
简化格式:
数据类型 [] 数组名={};
int [] array1=new int[]{11,12,13,14};
int []array2={11 , 12,13,15};
String []array3=new String[]{"xioaming","xioahong"};
String []array4={"xioaming","xioahong"};
数组名为数组的地址值:
public static void main(String[] args) {
System.out.println("hello world");
int []arr={1,2,3,4,5};
System.out.println(arr);//[I@6f496d9f
}
1.[:表示当前是一个数组
2.I:表示当前数组里面的元素都是int类型的
3.@:表示一个间隔符号(固定格式)
4.后边的才是数组真正的地址
动态数组
数据类型 [] 数组名=new 数据类型[数组长度];
数组默认初始化值的规律
1.整数类型:默认初始化为0
2.小数类型:默认初始化0.0
3.字符类型:默认初始化值'/u0000'空格
4.布尔类型:默认false
5.引用数据类型:默认NULL
四、java内存分配
1.栈:方法运行使用的内存,比如main()方法运行时,进入方法栈中执行
2.堆:存储对象或者数组,new创建出的对象都存储在堆内存
3.方法区:存储可以运行的class文件
4.本地方法栈:JVM在使用操作系统功能的时候使用,和我们开发无关
5.寄存器:给CPU使用,和我们开发无关
总结:
1.只要是new出来的都在堆里面开辟了一个小空间
2.如果new了多次,那么在堆里面有多个小空间,每个小空间中都有各自的数据
总结:当两个数字指向同一个小空间时,其中一个数组对小空间中的值发生了改变,那么其他数组再次访问的时候都是修改之后的结果了。
五、方法:是程序中最小的执行单元
重复的代码、具有独立功能的代码可以抽取到方法中
方法的好处:
1.提高代码的复用性2.提高代码的可维护性
方法的作用:把一些代码打包在一起,用到的时候就调用
1.方法定义
方法必须先定义后调用
public static 返回值类型 方法名(参数){
方法体;
return 返回值;
}
形参:全称形式参数,是指方法定义中的参数
实参:全称实际参数,方法调用中的参数
注:方法调用时,参数的数量与类型必须与方法定义中小括号里面的变量一一对应,否则程序将报错。
方法定义的小技巧:
1.我要干什么?-----方法体
2.我干这件事情需要什么才能完成?------形参
2.方法调用
方法注意事项
1.方法不调用就不执行
2.方法与方法之间是平级关系,不能互相嵌套定义
3.方法的编写顺序和执行顺序无关
4.方法的返回值类型为void,表示该方法没有返回值,如果返回值的方法可以省略return语句不写。如果要编写return,后面不能跟具体的数据
5.return语句下面,不能编写代码,因为永远执行不到,属于无效代码
3.方法重载:在同一个类中,方法名相同,参数不同的方法。与返回值无关
参数顺序不同可以构成重载,但是不建议
基本数据类型:变量里存储的是真实的数据
引用数据类型:new出来的都是引用数据类型,变量中存储的是地址值。引用:使用其他空间的数据
练习:
1.产生验证码
import java.util.Random;
/*需求:
定义方法实现随机产生一个5位的验证码
验证码格式:
长度为5
前四位是大写或小写字母
最后一位是数字
* */
public class hellowworld {
public static void main(String[] args) {
verificationCode();
}
public static void verificationCode() {
//1.将小写字母和大写字母存数组中
char []vc=new char[52];
for(int i=0;i<vc.length;i++){
if(i<=25){
vc[i]=(char)(97+i);//存小写字母
}else {//存大写字母
vc[i] = (char) (((int) ('A')) + i - 26);
}
}
//定义字符串
String code="";
//2.随机取四个字母
Random r=new Random();
for(int j=0;j<4;j++){
int randomIndex=r.nextInt(vc.length);
code=code+vc[randomIndex];
}
//3.随机取一个数字
int number=r.nextInt(10);
code=code+number;
System.out.println(code);
}
}
2.加密解密
import java.util.Scanner;
/*需求:
某系统的数字密码(大于0)比如1983,采用加密方式进行传输,
规则如下:
每位数加上5,在对10求余
最后将所有数字反转,得到一串新数
* */
public class hellowworld {
public static void main(String[] args) {
digitalEncryption();
}
public static void digitalEncryption() {
Scanner sc = new Scanner(System.in);
int password = sc.nextInt();
int copy = password, code= 0;
while (copy % 10 != 0) {
int num = copy % 10;
code = ((num + 5) % 10) +code* 10;
copy = copy / 10;
}
System.out.println(code);
}
}
六、二维数组:
数组中存数组
1.二维数组的初始化
静态初始化:
数据类型 [][]数组名=new 数据类型[][]{{元素1,元素2},{元素1,元素2}};
eg:
int [][]arr=new int[][]{{1,2},{3,4}};
简化格式:数据类型[][]数组名={{元素1,元素2},{元素1,元素2}};
eg:
int [][]arr={{11,22},{33,44}};//符合阿里巴巴代码规范
int arr[][]={{11,22},{33,44}};//也可以,但不推荐
//建议这样定义,把每一个一维数组,单独写一行
//注意:每一个一维数组其实是二维数组中的元素,
//所以每一个一维数组之间需要用逗号隔开,最后一个一维数组后面不需要加逗号
int [][]arr={
{1,2},
{3,4}
};
//二维数组的遍历
int [][]arr={
{1,2,8},
{3,4,9}
};
//外循环:遍历二维数组,得到里边的每一个一维数组
for(int i=0;i< arr.length;i++){
//内循环:遍历一维数组,得到里面的每一个元素
for(int j=0;j<arr[i].length;j++){
System.out.print(arr[i][j]+" ");
}
System.out.println();
}
二维数组的动态初始化
数据类型 [][]数组名=new 数据类型[m][n];
m表示这个二维数组,可以存放多少个一维数组,n表示每一一维数组,可以存放多少个元素
eg:
int [][]arr=new int[2][3];
二维数组的内存图
特殊情况1:初始:
赋值后:
七、面向对象
设计对象并使用
1.类和对象
类:是对像共同特征的描述
对象:是真是存在的具体东西
在java中,必须先设计类,才能获得对象。
如何定义类
定义类:
public class 类名{
1.成员变量(代表属性,一般是名词)
2.成员方法(代表行为,一般是动词)
3.构造器
4.代码块
5.内部类
}
得到类对象:
类名 对象名=new 类名();
使用方法:
访问属性:
对象名.成员变量
访问行为:
对象名。方法名(...)
eg:
public class Phone {
//属性(成员变量)
String brand;
double prices;
//行为(方法)
public void call(){
System.out.println("手机在打电话");
}
public void playGame(){
System.out.println("手机在玩游戏");
}
}
//测试类
public class PhoneTest {
//创建对象
public static void main(String[] args) {
Phone p=new Phone();
p.brand="小米";
p.prices=199.86;
System.out.println(p.brand);
System.out.println(p.prices);
p.playGame();
p.call();
}
}
类的几个补充注意事项
1.用来描述一类事物的类,专业叫做:Javabean类。
在Javabean类中,不写main方法。
2.编写main方法的类,叫做测试类
我们可以在测试类中创建javabean类的对象并进行赋值调用。
3.类名首字母建议大写,需要见名知义,驼峰模式
4.一个java文件可以定义多个class类,且只能一个类时public修饰,而且public修饰的类名必须成为代码文件名。实际开发中建议还是一个文件定义一个class类
5.成员变量的完整定义格式是: 修饰符 数据类型 变量名称 =初始化值;一般无需指定初始化值,存在默认值。
对象的成员变量的默认值规则:
开发中类的设计
可以提取名词--》属性
可以提取动词--》行为
2.封装
告诉我们:如何正确设计对象的属性和方法。
原则:对象代表什么,就得封装对应的数据,并提供数据对应的行为
eg: 人关门
关门这个方法是门的方法。
private关键字
- 是一个权限修饰符
- 可以修饰成员(成员变量和成员方法)
- 被private修饰的成员只能在本类中才能访问
- 针对private修饰的成员变量,如果需要被其他类使用,必须提供相应的操作
- 提供“setXxx(参数)”方法,用于给成员变量赋值,方法用public修饰
- 提供“getXxx()”方法,用于获取成员变量的值,方法用public修饰
public class girlFriend {
private String name;
private int age;
//针对每一个私有化的成员变量,都要提供get和set方法
//name
public void setName(String name) {
this.name = name;
}
public String getName(){
return name;
}
//age
public void setAge(int age){
if(age>0&&age<=100)
this.age=age;
else
System.out.println("非法输入");
}
public int getAge(){
return age;
}
public void sleep(){
System.out.println("女朋友在睡觉");
}
}
//测试类
public class girlFriendTest {
public static void main(String[] args) {
girlFriend gf=new girlFriend();
gf.setName("Сʫʫ");
gf.setAge(-1);
System.out.println(gf.getName());
System.out.println(gf.getAge());
gf.sleep();
}
}
局部变量和成员变量
局部变量和成员变量重名是按照就近原则,要用成员变量就用 “this. +成员变量”
this的作用:区别成员变量和局部变量
3.构造方法
也叫构造器、构造函数
作用:在创建对象的时候,由虚拟机自动调用,给成员变量进行初始化
构造方法有:
1.无参数构造方法:初始化对象时,成员变量的数据均采用默认值
2.有参数构造方法:初始化对象时,同时给成员变量赋值
格式:
修饰符 类名(参数){
方法体;
}
特点:
1.方法名与类名相同,大小写也要一致
2.没有返回值类型,连void也没有
3.没有具体的返回值(不能由return带回结果数据)
执行时机:
1.创建对象的时候由虚拟机调用,不能手动调用构造方法
2.每创建一次对象,就会调用一次构造方法
构造方法注意事项:
1.构造方法的定义:
- 如果没有定义构造方法,系统将给出一个默认的无参数构造方法
- 如果定义了构造方法,系统将不提供默认的构造方法
2.构造方法的重载
- 带参构造方法,和无参数构造方法,两者方法名相同,但是参数不同,这叫构造方法的重载
3.推荐使用方法
- 无论是否使用,都手动书写无参数构造方法,和带全部参数的构造方法
八、标准的JavaBean
- 类名需要见名知意,驼峰命名
- 成员变量使用private修饰
- 至少提供两个构造方法
- 无参构造方法
- 带全部参数的构造方法
- 成员方法
- 提供每个成员变量对应的setX()/getX()
- 如果还有其他行为,也需要写上
package test01;
public class girlFriend {
private String name;
private String password;
private int age;
//无参构造方法
public girlFriend() {
}
//有全部参数的构造方法
public girlFriend(String name, String password, int age) {
this.name = name;
this.password = password;
this.age = age;
}
//name
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
//password
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
//age
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
对象内存图
一个对象的内存图:
在study()方法使用完后,study方法出栈,程序结束,main()方法也出栈,之后堆内存中会被回收
两个对象的内存图
两个引用指向同一个对象:当两个引用其中一个对这个对象的内容进行改变后,另一个引用再次访问时,就是改变后的值。
stu1=NULL:
基本数据类型和引用数据类型
基本数据类型:数据值是存储在自己的空间中
特点:赋值给其他变量,赋的真实的值
引用数据类型:数据值是存储在其他空间中,子集空间中存储的是地址值
特点:赋值给其他变量,赋的是地址。
this的内存原理:
this的本质:代表方法调用者的地址值
成员变量和局部变量
成员变量:类中方法外的变量
局部变量:方法中的变量
九、API与字符串
API(Application Programming Interface):应用程序编程接口
简单理解:API就是别人已经写好的东西,我们不需要自己编写,直接使用即可。
java API :指的就是jdk中提供的各种功能的java类
这些类将底层的实现封装了起来,我们不需要关心这些类时如何实现的,只需要学习这些类如何使用即可
API帮助文档:帮助开发人员更好使用和查询API的一个工具
使用方法:
1.打开API帮助文档
2.点击显示,并找到索引下面的输入
3.在输入框中输入类名并点击显示
4.查看类所在的包
5.查看类的描述
6.查看构造方法
7.查看成员方法
字符串
1.java.lang.String类代表字符串,java程序中的所有字符串文字都为此类的对象。
使用时不用导包。
2.字符串的内容是不会发生改变的,它的对象在创建后不能被更改。
String name="哈哈";
name="你好";
System.out.println(name);
//实际创建了两个对象
String name="哈哈";
dongzuo="你好";
System.out.println(name+dongzuo);
/实际创建了三个对象
构造方法
1.直接赋值
//直接赋值方式获得一个字符串对象(用的最多)
String s1 = "abc";
System.out.println(s1);//abc
2.new
//使用new的方式来获取一个字符串对象(相当于“”)
String s2=new String();
System.out.println("你好"+s2+"不好");//你好不好
//传递一个字符串,根据传递的字符串内容再创建一个新的字符串对象(很少使用)
String s3=new String("abcd");//abcd
System.out.println(s3);
//传递一个字符数组,根据字符数组的内容再创建一个新的字符串对象
//需求:修改字符串内容
//abc--->{'a','b','c'}---->{'Q','b','c'}----->"Qbc"
char []chs={'a','b','c'};
String s4=new String(chs);//abc
System.out.println(s4);
//传递一个字节数组,根据字节数组的内容再创建一个新的字符串对象
//应用场景:以后在网络当中传输的数据其实都是字节信息
//我们一般要把字节信息进行转换,转成字符串,此时就要用到这个构造了
byte[] bytes={97,98,99};
String s5=new String(bytes);
System.out.println(s5);//abc
内存模型:String Table(串池)在jdk7版本开始从方法区挪到了堆内存
直接赋值:--节约内存-代码最简单
当使用双引号直接赋值时,系统会检查该字符串在串池中是否存在。不存在:创建新的;存在:复用。
用new创建字符串对象:
常用方法:
1.比较
==号比的到底是什么?
字符串比较--比较内容
String s1 = "abc";
String s2 = new String("abc");
//==号比较
System.out.println(s1 == s2);//false
//比较字符串对象中的内容是否相同
boolean result1 = s1.equals(s2);
System.out.println(result1);//true
String s3 = new String("Abc");
boolean result2 = s1.equals(s3);
System.out.println(result2);//false
boolean result3 = s1.equalsIgnoreCase(s3);
System.out.println(result3);//true
结论:
以后只要想比较字符串的内容,就必须要用String里面的方法
练习:
//1.键盘录入一个abc
Scanner sc=new Scanner(System.in);
String s1=sc.next();//abc 是new出来的
//2.代码中在定义一个字符串abc
String s2="abc";
//3.用==比较,这两者能一样吗?
System.out.println(s1==s2);//false
//结论:
//以后只要想比较字符串的内容,就必须要用String里面的方法
录入一个字符串,并遍历
//键盘录入一个字符串,并遍历
Scanner sc=new Scanner(System.in);
String s=sc.next();
for(int i=0;i<s.length();i++){
char c=s.charAt(i);
System.out.print(c+" ");
}
金额转换:
public static void main(String[] args) {
//1.键盘录入一个金额
Scanner sc=new Scanner(System.in);
int money;
while(true){
System.out.println("请录入一个金额:");
money=sc.nextInt();
if(money>=0&&money<=9999999){
break;
}
else{
System.out.println("金额无效!");
}
}
//定义一个变量用来表示钱的大写
String moneyStr=MoneyStr(money);
System.out.println(moneyStr);
}
//对money进行变换
public static String MoneyStr(int money) {
String []CapitalNumber={"零","壹","贰","叁","肆","伍","陆","柒","捌","玖"};
String []DanWei={"佰","拾","万","仟","佰","拾","元"};
String moneyStr="";
//2.得到money里面每一位数字,再转成中文
while(money!=0){
int ge=money%10;
moneyStr=CapitalNumber[ge]+moneyStr;
money=money/10;
}
//3.补齐七位数
int cout=7-moneyStr.length();
for(int i=0;i<cout;i++){
moneyStr="零"+moneyStr;
}
String result="";//最终结果
//4.插入单位
for(int i=0;i<moneyStr.length();i++){
char c=moneyStr.charAt(i);
result=result+c+DanWei[i];
}
return result;
}
- String substring(int beginindex,int endindex) 截取
- 注意点:包头不包尾,包左不包右。只有返回值才是截取的小串。
- String substring(int beginindex) 截取到末尾
- charAt() 返回一个字符串的指定位置的字符,索引是从[0,length-1].比如:
- str.charAt(0)检索str中的第一个字符,str.charAt(str.length()-1)检索最后一个字符。
//从身份证中获取信息
String id="41138120060510302X";
String year=id.substring(6,10);
String month=id.substring(10,12);
String day=id.substring(12,14);
System.out.println("人物信息为:");
System.out.println("出生年月日:"+year+"年"+month+"月"+day+"日");
//获取性别
char gender=id.charAt(16);//'3'
int num=gender-48;
if(num%2==0){
System.out.println("性别为:女");
}else{
System.out.println("性别为:男");
}
- String.replace(char oldchar,char newchar) 替换
String num = "1,2,3";
String[] arr = {"1","2","4"};
for(int i=0;i<arr.length;i++){
num=num.replace(arr[i],"*");
}
System.out.println(num);
十、StringBuilder和StringJoiner概述
StringBuilder概述
使用场景:
1.字符串的拼接
2.字符串的反转
StringBuilder 可以看成是一个容器,创建之后里面的内容是可变的
- 作用:提高字符串的操作效率
构造方法:
- public StringBuilder() 创建一个空白可变的字符串对象,不含有任何内容
- public StringBuilder(String str) 根据字符串的内容,来创建可变字符串对象
StringBuilder常用的方法
- public StringBuilder append(任意类型) 添加数据,并返回对象本身
- public StringBuilder reverse() 反转容器中的内容
- pubilc int length() 返回长度(字符出现的个数)
- public String toString() 通过toString就可以实现把StringBuilder转换成String
注意:
因为StringBuilder是java已经写好的类,java在底层对他做了一些特殊处理,打印对象不是地址值而是属性值。
StringBuilder sb = new StringBuilder("ABC");
sb.append("123");
sb.reverse();
System.out.println(sb);
String str = sb.toString();
System.out.println(str);
链式编程:当我们在调用一个方法的时候,不需要用变量接收他的结果们可以继续调用其他方法。
Scanner sc=new Scanner(System.in);
System.out.println("请输入一个字符串:");
String str=sc.next();
//反转键盘录入的字符串
String result=new StringBuilder().append(str).reverse().toString();
if(str.equals(result)){
System.out.println("是反转字符串");
}else{
System.out.println("不是反转字符串");
}
StringJoiner概述
StringJoiner跟StringBuilder一样,也可以看成是一个容器,创建之后里面的内容是可变的。
作用:提高字符串的操作效率,而且代码编写特别简洁,但是目前市场上很少有人用。
JDK8出现的一个可变的操作字符串的容器,可以高效,方便的拼接字符串。
构造方法:
- Public StringJoiner(间隔符号) 创建一个StringJoiner对象,指定拼接时的间隔符号
- Public StringJoiner(间隔符号,开始符号,结束符号) 创建一个StringJoiner对象,指定拼接时的间隔符号、开始符号、结束符号。
- public StringJoiner add(添加的内容) 添加数据,并返回对象本身
- Public int length()返回长度(字符出现的个数)
- public String toString() 返回一个字符串(该字符串就是拼接之后的结果)
StringJoiner sj=new StringJoiner(",","[","]");
sj.add("aaa").add("bbb").add("ccc");
System.out.println(sj);
原理扩展
字符串原理
扩展底层原理1:字符串存储的内存原理
- 直接赋值会复用字符串常量池中的
- new出来不会复用,而是开辟一个新的空间
扩展底层原理2:==号比较的到底是什么
- 基本数据类型比较数据值
- 引用数据类型比较地址值
扩展底层原理3:字符串拼接的底层原理
如果没有变量参与,都是字符串直接相加,编译之后就是拼接之后的结果
如果有变量参与,会创建新的字符串,浪费内存
拼接时右边无变量:
拼接时右边有变量:
扩展底层原理4:StringBuilder提高效率原理图
所有要拼接的内容都会往StringBuilder中放,不会创建很多无用的空间,节约内存
常见面试题
扩展底层原理5:StringBuilder源码分析
- 默认创建一个长度为16的字节数组
- 添加的内容长度小于16,直接存
- 添加的内容大于16会扩容(原来的容量*2+2)
- 如果扩容之后还不够,以实际长度为准
练习:
1.罗马数字转换
package test02;
import java.util.Scanner;
public class hellowworldTest {
public static void main(String[] args) {
String str;
while (true) {
//1.录入字符串
System.out.println("请输入一个字符串:");
Scanner sc=new Scanner(System.in);
str=sc.next();
//2.判断字符串是否符合要求
boolean request=Judge(str);
if(request){
break;
}else{
System.out.println("当前的字符串不符合要求");
continue;
}
}
// //3.用罗马数字进行拼接
// str=Replace(str);
// System.out.println(str);
StringBuilder sb=new StringBuilder();
for(int i=0;i<str.length();i++){
char c=str.charAt(i);
String s=changeLuoMa(c);
sb.append(s);
}
System.out.println(sb);
}
public static String changeLuoMa(char number){
String str=switch(number){
case '0'->"";
case '1'->"Ⅰ";
case '2'->"Ⅱ";
case '3'->"Ⅲ";
case '4'->"Ⅳ";
case '5'->"Ⅴ";
case '6'->"Ⅵ";
case '7'->"Ⅶ";
case '8'->"Ⅷ";
case '9'->"Ⅸ";
default -> str="" ;
};
return str;
}
// public static String Replace(String str){
// char [] luoma={' ','Ⅰ','Ⅱ','Ⅲ','Ⅳ','Ⅴ','Ⅵ','Ⅶ','Ⅷ','Ⅸ'};
// for(int i=0;i<str.length();i++){
// char c=str.charAt(i);
// int index=(((int)c)-'0');
// str=str.replace(c,luoma[index]);
//
// }
// return str;
//
// }
public static boolean Judge(String str){
if(str.length()>9){
return false;
}
for(int i=0;i<str.length();i++){
char c=str.charAt(i);
if(c<'0'||c>'9'){
return false;
}
}
return true;
}
}
str.toCharArray() 将字符串转换为字符数组。
package test02;
public class hellowworldTest {
public static void main(String[] args) {
//套路:
//修改字符串的内容
//1.用substring进行截取,把左边的字符截取出来拼接到右侧去
//2.可以把字符串先变成一个字符数组,然后调整字符数组里面数据,最后再把字符数组变成字符串
String strA = "abcde";
String strB = "cefab";
//1.旋转字符串,并比较
int i = 0;//记录比较次数
while (!strA.equals(strB) && i < strA.length()) {
strA = rotate(strA);
i++;
// System.out.println(strA+" "+i);
}
if (strA.equals(strB)) {
System.out.println("TRUE");
} else {
System.out.println("FALSE");
}
}
//作用:旋转字符串,将左边字符串旋转到右边去
//形参:旋转前的字符串
//返回值:旋转后的字符串
public static String rotate(String str) {
// //1.用substring截取
// char first = str.charAt(0);
// String end = str.substring(1);
// return end + first;
//2.可以把字符串先变成一个字符数组,然后调整字符数组里面数据,最后再把字符数组变成字符串
//"ABC" ['A','B','C']
char[] arr = str.toCharArray();
//拿到0索引上的字符
char first = arr[0];
//把剩余的字符依次往前挪一个位置
for (int i = 1; i < arr.length; i++) {
arr[i - 1] = arr[i];
}
arr[arr.length - 1] = first;
//利用字符数组创建一个字符串对象
String result = new String(arr);
return result;
}
}
十一、集合
自动扩容
集合存储数据类型的特点:只能存引用数据类型,基本数据类型存储时要变成包装类
ArrayList
在java.util包下,需要导包
泛型:限定集合中存储数据的类型
ArrayList<String> list=new ArrayList<>();
//此时我们创建的是ArrayList的对象,而ArrayList是java已经写好的一个类
//这个类在底层做了一些处理
// 打印对象不是地址值,而是集合中存储的数据内容
// 在展示的时候会拿[]把所有的数据进行包裹
System.out.println(list);//[]
ArrayList成员方法
//1.创建一个对象
ArrayList<String> list = new ArrayList<>();
//2.添加元素--返回值是true
list.add("aaa");
list.add("bbb");
list.add("ccc");
list.add("ddd");
list.add("bbb");
// //3.删除元素
// boolean result1 = list.remove("aaa");
// System.out.println(result1);//true
//
// boolean result2 = list.remove("eee");//删除内容不存在,删除失败
// System.out.println(result2);//false
// //3.根据索引删除
//
// String str = list.remove(2);//返回被删除的字符串
// System.out.println(str);//ddd
// //4.修改
// String str = list.set(1, "eee");//返回被覆盖的元素
// System.out.println(str);//bbb
//5.查询
// String str=list.get(1);
// System.out.println(str);//bbb
//遍历--list.fori
for (int i = 0; i < list.size(); i++) {
String str= list.get(i);
System.out.print(str+" ");//aaa bbb ccc ddd bbb
}
System.out.println(list);
集合练习:
集合存入String和int类型
// ArrayList<String> list=new ArrayList<>();
//
// list.add("aaa");
// list.add("aaa");
// list.add("aaa");
// list.add("aaa");
// list.add("aaa");
//
// System.out.print("[");
// for (int i = 0; i < list.size(); i++) {
// if(i== list.size()-1){
// System.out.print(list.get(i));
// }else{
// System.out.print(list.get(i)+",");
// }
// }
// System.out.print("]");
ArrayList<Integer> list=new ArrayList<>();
list.add(1);
list.add(1);
list.add(1);
list.add(1);
list.add(1);
System.out.println(list);
集合存入自定义类
Scanner sc=new Scanner(System.in);
ArrayList<girlFriend> list=new ArrayList<>();
for(int i=0;i<3;i++){
girlFriend gf=new girlFriend();
System.out.println("请输入姓名:");
String name=sc.next();
gf.setName(name);
System.out.println("请输入年龄:");
int age=sc.nextInt();
gf.setAge(age);
list.add(gf);
}
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i).getName()+" "+list.get(i).getAge());
}
package test01;
import java.util.ArrayList;
public class girlFriendTest {
public static void main(String[] args) {
//定义集合
ArrayList<girlFriend> list=new ArrayList<>();
//存入三个对象
girlFriend gf1=new girlFriend("小米",1000);
girlFriend gf2=new girlFriend("苹果",8000);
girlFriend gf3=new girlFriend("锤子",2999);
list.add(gf1);
list.add(gf2);
list.add(gf3);
ArrayList<girlFriend> gfInFoList=judgePrice(list);
for (int i = 0; i < gfInFoList.size(); i++) {
girlFriend gf=gfInFoList.get(i);
System.out.println(gf.getBrand()+" "+gf.getPrice());
}
}
//返回价格低于3000的手机信息
//技巧:
//如果我们要返回多个数据,可以把这些数据放在一个容器里,再把容器返回
//集合 数组
public static ArrayList<girlFriend> judgePrice(ArrayList<girlFriend> list){
ArrayList<girlFriend> resultList=new ArrayList<>();
for (int i = 0; i < list.size(); i++) {
girlFriend gf=list.get(i);
int price=gf.getPrice();
if(price<3000){
resultList.add(gf);
}
}
return resultList;
}
}
十二、面向对象进阶
static
static表示静态,是java中的一个修饰符,可以修饰成员方法,成员变量
被static修饰的成员变量,叫做静态变量
特点:
- 被该类所有对象共享
- 不属于对象,属于类
- 随着类的加载而加载,优先于对象存在
调用方法:
- 类名调用(推荐)
- 对象名调用
被static修饰的成员方法,叫做静态方法。
- 多用在测试类和工具类中
- javabean类中很少会使用
工具类:帮助我们做一些事情的,但是不描述任何事物的类
- 类名见名知意
- 私有化构造方法
- 方法定义为静态
javabean类:用来描述一类事物的类
测试类:用来检查其他类是否书写正确,带有main方法的类,是程序的入口
package staticdemo1;
public class ArrayUtil {
//私有化构造方法
//目的:为了不让外界创建他的对象
private ArrayUtil(){}
//需要定义为静态的,方便调用
public static String printArr(int []arr){
StringBuilder sb=new StringBuilder();
sb.append("[");
for (int i = 0; i < arr.length; i++) {
if(i==arr.length-1){
sb.append(arr[i]);
}else{
sb.append(arr[i]).append(",");
}
}
sb.append("]");
return sb.toString();
}
public static double getAverage(double[]arr){
double sum=0;
for (int i = 0; i < arr.length; i++) {
sum=sum+arr[i];
}
return sum/arr.length;
}
}
---------------------------------------------------------------------
package staticdemo1;
public class TestDemo1 {
public static void main(String[] args) {
int []arr1={1,2,3,4,5};
String s=ArrayUtil.printArr(arr1);
System.out.println(s);
double []arr2={12.5,13.5,45.2,12.5,12.3};
double end=ArrayUtil.getAverage(arr2);
System.out.println(end);
}
}
static的注意事项
- 静态方法只能访问静态变量和静态方法
- 非静态方法可以访问静态变量或者静态方法,也可以访问非静态的成员变量和非静态的成员方法、静态方法中没有this关键字
继承
java中提供一个关键字extend,用这个关键字,我们可以让一个类和另一个类建立起起继承关系。
public class 子类 extends 父类{}
eg:
public class Student extends Person{}
Student称为子类(派生类),Person称为父类(基类或超类)。
使用继承的好处:
- 可以把多个子类中重复的代码抽取到中,提高代码的复用性。
- 子类可以在父类的基础上,增加其他的功能,使子类更强大。
当类与类之间,存在相同(共性)的内容,并满足子类是父类中的一种,就可以考虑继承,来优化代码。
继承的特点:
- java只支持单继承,不支持多继承,但支持多层继承。
- 单继承:一个子类只能有一个父类。
- 不支持多继承:子类不能同时继承多个父类。
- 多层继承:子类A继承父类B,父类B可以继承父类C。
- 每一个类都直接或者间接的继承与Object。
子类只能访问父类中非私有的成员。
子类能继承父类哪些内容?
构造方法:
继承中成员变量和成员方法的访问特点:
成员变量的访问特点:
就近原则:谁离我近我就用谁
先局部位置--再本类的成员位置---后父类成员位置,一级一级往上找
成员方法的访问特点:
直接调用满足就近原则:谁离我近,我就用谁
super调用,直接访问父类
方法的重写
当父类的方法不能满足子类现在的需求时,需要进行方法重写。
书写格式:在继承体系中,子类出现了和父类中一模一样的方法声明,我们就成称子类这个方法是重写的方法。
@Override重写注解
1.@Override是放在重写后的方法上,校验子类重写时语法是否正确。
2.加上注解后如果有红色波浪线,表示语法错误。
3.建议重写方法都加@Override注解,代码安全,优雅!
方法重写注意事项和要求:
1.重写方法的名称、形参列表必须与父类中的一致。
2.子类重写父类方法时,访问权限子类必须大于等于父类(暂时了解:空着不写<protected<public)。
3.子类重写父类方法时,返回值类型子类必须小于等于父类。
4.建议:重写的方法尽量和父类保持一致
5.只有被添加到虚方法表中的方法才能被重写
继承中构造方法的访问特点
- 父类的构造方法不会被子类继承
- 子类中所有的构造方法默认先访问父类中的无参构造,再执行自己
- 为什么?
- 子类在初始化的时候,有可能会使用到父类中的数据,如果父类没有完成初始化,子类将无法使用父类的数据。
- 子类初始化之前,一定要调用父类构造方法先完成父类数据空间的初始化。
- 怎么调用父类构造方法的
- 子类构造方法的第一行语句默认都是:super(),不写也存在,且必须在第一行
- 如果想调用父类有参构造,必须手写super进行调用。
- 为什么?
package staticdemo1;
public class TestDemo1 {
public static void main(String[] args){
Student s1=new Student();
//输出:父类的无参构造
// 子类的无参构造
Student s2=new Student("张三",16);
System.out.println(s2.name+" "+s2.age);//输出:张三 16
}
}
class Person{
String name;
int age;
public Person() {
System.out.println("父类的无参构造");
}
public Person(String name,int age) {
this.name = name;
this.age=age;
}
}
class Student extends Person{
public Student() {
//子类中隐藏的super去访问父类的无参构造
System.out.println("子类的无参构造");
}
public Student(String name, int age) {
super(name, age);//调用父类的有参构造
}
}
this、super使用总结:
- this:理解为一个变量,表示当前方法调用者的地址值。
- super:代表父类存储空间。
package staticdemo1;
public class TestDemo1 {
public static void main(String[] args){
Student s1=new Student();
System.out.println(s1.name+" "+s1.age+" "+s1.school);//null 0 传智大学
Student s2=new Student("张三",16,"黑马");
System.out.println(s2.name+" "+s2.age+" "+s2.school);//张三 16 黑马
}
}
class Person{
String name;
int age;
public Person() {
System.out.println("父类的无参构造");
}
public Person(String name,int age) {
this.name = name;
this.age=age;
}
}
class Student extends Person{
//需求:
//默认为传智大学
String school;
public Student() {
//表示调用本类的其他构造方法;
//细节:虚拟机就不会再添加super()方法。因为其他构造中有
this(null,0,"传智大学");
}
public Student(String name, int age,String school) {
super(name,age);
this.school=school;
}
}
多态
什么是多态?
同类型的对象,表现出不同形态,对象的多种形态
多态的表现形式
父类类型 对象名称=子类对象;
多态的前提
- 有继承/实现关系
- 有父类引用指向子类对象
- 有方法重写
多态调用成员的特点
调用成员变量:编译看左边,运行也看左边
编译看左边:javac编译代码的时候,会看左边的父类中有没有这个变量,如果有,编译成功,如果没有编译失败。
运行也看左边:java运行代码的时候,实际获取的就是左边父类中成员变量的值。
调用成员方法:编译看左边,运行看右边
编译看左边:javac编译代码的时候。会看左边的父类中有没有这个方法,如果有,编译成功,如果没有编译失败。
运行看右边:java运行代码的时候,实际上运行的是子类中的方法。
成员变量:在子类的对象中,会把父类的成员变量也继承下的。
成员方法:如果子类对方法进行了重写,那么在虚方法表中是会把父类的方法进行覆盖的
多态的优缺点
- 优势:
- 在多态形式下。右边对象可以实现解耦合,便于扩展和维护。
- 定义方法的时候,使用父类类型为参数,可以接受所有子类对象,体现多态的扩展性与便利
- 弊端:
- 不能调用子类特有的功能
- 原因:当调用成员方法时,编译看左边,运行看右边。那么在编译的时候会先检查左边的父类中有没有这方法,如果没有直接报错。
- 解决方法:变回子类类型就可以了,注意转换时不能瞎转没如果转成其他类型,会报错。
package staticdemo1;
public class test {
public static void main(String[] args) {
Animal a=new dog();
//类型强转
//方法·1
// if(a instanceof dog){
// dog d=(dog)a;
// d.LookHome();
// }else if(a instanceof cat){
// cat c=(cat)a;
// c.CatchMouse();
// }else{
// System.out.println("没有这个类型,无法转换");
// }
//方法2
if(a instanceof dog d){
d.LookHome();
}else if(a instanceof cat c){
c.CatchMouse();
}else{
System.out.println("没有这个类型,无法转换");
}
}
}
引用数据类型的类型转换,有几种方式?
自动类型转换、强制类型转换
强制类型转换能解决什么问题?
- 可以转换成真正的子类类型,从而调用子类独有的功能
- 转换类型与真实对象类型不一致会报错
- 转换的时候用 instanceof 关键字进行判断
package staticdemo1;
public class test {
public static void main(String[] args) {
Animal a=new cat(3,"灰");
person p=new person("老王",30);
p.keepPet(a,"小鱼干");
Animal a2=new dog(2,"黑");
person p2=new person("老李",25);
p2.keepPet(a2,"骨头");
}
}
-----------------------------------------------------
package staticdemo1;
public class Animal {
//属性
private int age;
private String color;
public Animal() {
}
public Animal(int age, String color) {
this.age = age;
this.color = color;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public void eat(String something){
if(this instanceof dog d){
d.eat(something);
}else if(this instanceof cat c){
c.eat(something);
}
}
}
---------------------------------------------
package staticdemo1;
public class cat extends Animal{
public cat() {
}
public cat(int age, String color) {
super(age, color);
}
public void catchMouse(){
System.out.println("猫逮老鼠");
}
@Override
public void eat(String something) {
System.out.println(getAge()+"岁的"+getColor()+"颜色的猫眯着眼睛侧着头吃"+something);
}
}
----------------------------------------------
package staticdemo1;
public class dog extends Animal{
public dog() {
}
public dog(int age, String color) {
super(age, color);
}
public void lookHome(){
System.out.println("狗看家");
}
@Override
public void eat(String something) {
System.out.println(getAge()+"岁的"+getColor()+"颜色的狗两只前腿死死的抱住"+something+"猛吃");
}
}
----------------------------------------------------------------
package staticdemo1;
//饲养员
public class person {
private String name;
private int age;
public person() {
}
public person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
//行为
public void keepPet(Animal a,String something){
System.out.print("年龄为"+getAge()+"岁的"+getName()+"养了一只"+a.getColor()+"颜色的"+a.getAge()+"岁的");
if(a instanceof dog d){
System.out.println("狗");
d.eat(something);
}else if(a instanceof cat c){
System.out.println("猫");
c.eat(something);
}
}
}
什么是包?
包就是文件夹。用来管理各种不同功能的java类,方便后期维护代码维护。
包名的规则:公司域名反写+包的作用,需要全部英文小写,见名知意。
全类名/全限定名
包名+类名
eg:
使用其他类的规则
使用其他类时,需要使用全类名
- 使用同一个包中的类时,不需要导包
- 使用java.lang包中的类时,不需要导包
- 其他情况都需要导包
- 如果同时使用两个包中的同名类,需要用全类名
final--最终的
可以修饰方法、类、变量。
方法:表明该方法时最终方法,不能被重写
类:表明该类是最终类,不能被继承
变量:叫做常量,只能被赋值一次
常量
实际开发中,常量一般作为系统的配置信息,方便维护,提高可读性
常量的命名规范:
- 单个单词:全部大写
- 多个单词:全部大写,单词之间用下划线隔开
细节:
final修饰的变量是基本类型:那么变量存储的数据值不能发生改变
final修饰的变量是引用类型:那么变量存储的是地址值不能发生改变,对象内部的可以改变。
private static final PI="3.14159";
权限修饰符
- 权限修饰符:是用来控制一个成员能够被访问的范围的。
- 可以修饰成员变量,方法,构造方法,内部类。
权限修饰符的分类:
有四种作用范围:由小到大:
private<空着不写(默认)<protected<public
权限修饰符使用规则
实际开发中,一般只用private和public
使用时一般:
- 成员变量私有
- 方法公开
特例:如果方法中的代码时抽取其他方法中共性代码,这个方法一般也私有。
代码块
局部代码块
写在方法里面的代码块
构造代码块
1.写在成员位置的代码块
2.作用:可以把多个构造方法中的重复代码抽取出来
3.执行时机:我们在创建本类对象的时候会先执行构造代码块在执行构造方法
渐渐淘汰了,不够灵活
如果构造方法中有重复代码,可以用以下两种方法:
静态代码块
格式:static{ }
特点:需要通过static关键字修饰,随着类的加载而加载,并且自动触发、只执行一次。
使用场景:在类加载的时候,做一些数据初始化且这些数据初始化只想使用一次的时候使用。
抽象类与抽象方法
- 抽象方法:
将共性的行为(方法)抽取到父类之后。由于每一个子类执行的内容是不一样,所以,再父类中不能确定具体的方法体。该方法就可以定义为抽象方法。
- 抽象类:如果一个类中存在抽象方法,那么该类就必须声明名为抽象类。
抽象方法的定义格式:
public abstract 返回值类型 方法名(参数列表);
抽象类的定义格式:
public abstract class 类名 {}
抽象类和抽象方法的注意事项:
- 抽象类不能实例化--即不能创建对象
- 抽象类中不一定有抽象方法,有抽象方法的类一定是抽象类
- 可以有构造方法
- 抽象类的子类
- 要么重写抽象类中的所有抽象方法
- 要么是抽象类
package test05;
public abstract class Animal {
private String name;
private int age;
public Animal() {
}
public Animal(String name, int age) {
this.name = name;
this.age = age;
}
/**
* 获取
* @return name
*/
public String getName() {
return name;
}
/**
* 设置
* @param name
*/
public void setName(String name) {
this.name = name;
}
/**
* 获取
* @return age
*/
public int getAge() {
return age;
}
/**
* 设置
* @param age
*/
public void setAge(int age) {
this.age = age;
}
public void drink(){
System.out.println("动物在喝水");
}
public abstract void eat();
}
------------------------------------------------------------
package test05;
public class Sheep extends Animal{
public Sheep() {
}
public Sheep(String name, int age) {
super(name, age);
}
@Override
public void eat() {
System.out.println("山羊吃草");
}
}
抽象方法和抽象类的意义
强制子类必须按照这种格式书写
接口
接口就是一种规则,是对行为的一种抽象
接口和抽象类:抽象类多用在父类中
格式:
public class 子类g extends 父类 implements 接口1,接口2....{
....
}
例子:
package test05;
public interface swim {
public abstract void swim();
}
------------------------------------------
package test05;
public class Dog extends Animal implements swim{
public Dog() {
}
public Dog(String name, int age) {
super(name, age);
}
@Override
public void eat() {
System.out.println("狗吃骨头");
}
@Override
public void swim() {
System.out.println("狗在游泳");
}
}
接口中成员的特点
- 成员变量
只能是常量
默认修饰符:public static final ...
- 构造方法
没有
- 成员方法
只能是抽象方法
默认修饰符:public abstract
- JDK7以前:接口中只能定义抽象方法
接口和类之间的关系
- 类和类之间的关系
- 继承关系,只能单继承,不能多继承,但是可以多层继承
- 如果实现类实现了最下面的子接口,那么就需要重写所有的抽象方法
- 类和接口的关系
- 实现关系,可以单实现,也可以多实现,还可以在继承一个类的同时实现多个接口-要重写里面所有的抽象方法
- 接口和接口的关系
- 继承关系,可以单继承,也可以多继承
例子:
package test05;
public class InterImp1 implements Inter3{
@Override
public void method1() {
}
@Override
public void method2() {
}
@Override
public void method3() {
}
}
----------------------------------------------------
package test05;
public interface Inter3 extends Inter1, Inter2{
public abstract void method3();
}
-------------------------------------------------------
package test05;
public interface Inter2 {
public abstract void method2();
}
-----------------------------------------------------
package test05;
public interface Inter1 {
public abstract void method1();
}
JDK8开始接口中的新增方法
JDK7以前:接口中只能定义抽象方法。
JDK8的新特性:接口中可以定义有方法体的方法(默认、静态)。
JDK9的新特性:接口中可以定义私有方法。
- 允许在接口中定义默认方法,需要使用关键字default修饰
- 作用:解决接口升级问题
- 接口中默认方法的定义格式:
- 格式:public default 返回值类型 方法名(参数列表){ }
- 范例:public default void show() {}
- 接口中默认方法的注意事项:
- 默认方法不是抽象方法,所以不强制重写。但是如果被重写,重写的时候必须去掉default关键字。
- public可以省略,default不能省略。
- 如果实现了多个接口,多个接口中存在相同名字的默认方法,子类就必须对该方法进行重写。
- 允许在接口中定义静态方法,需要用static修饰
- 接口中静态方法的定义格式:
- 格式:public static 返回值类型 方法名(参数列表) { }
- 范例:public static void show() {}
- 接口中静态方法的注意事项:
- 静态方法只能通过接口名调用,不能通过实现类名或者对象名调用
- public 可以省略,static不能省略
- 注意:
-
package test05; public interface Inter1 { public static void show1(){ System.out.println("Inter中的静态方法"); } } --------------------------------------------- package test05; public class InterImp1 implements Inter1{ //不叫重写,只是这两个接口中的静态方法同名而已 public static void show1(){ System.out.println("InterImp1中的静态方法"); } } --------------------------------------------- package test05; public class Test { public static void main(String[] args) { InterImp1 i1 =new InterImp1(); i1.show(); //调用接口中的静态方法 InterImp1.show1();//Inter中的静态方法 //调用实现类中的静态方法 InterImp1.show1();//InterImp1中的静态方法 //子类把父类继承下来的虚方法表里面的方法进行覆盖了,这才叫做重写 } }
-
- 接口中静态方法的定义格式:
JDK9新增的方法--解决重复代码
- 接口中私有方法(此方法只为接口提供服务,不需要外类访问)的定义格式
- 普通的私有方法,给默认方法服务的
- 格式一: private 返回值类型 方法名(参数列表){ }
- 范例一:private void show() {}
- 静态的的私有方法,给静态方法服务的
- 格式二:private static 返回值类型 方法名(参数列表){}
- 范例二:private static void method() { }
- 普通的私有方法,给默认方法服务的
package test06;
public interface InterA {
public default void show1(){
System.out.println("show1方法开始执行了");
show3();
}
public default void show2(){
System.out.println("show2方法开始执行了");
show3();
}
//普通的私有方法
private void show3(){
System.out.println("这里有100行show1,show2的重复代码");
}
public static void show4(){
System.out.println("show1方法开始执行了");
show6();
}
public static void show5(){
System.out.println("show2方法开始执行了");
show6();
}
//静态的私有方法
private static void show6(){
System.out.println("这里有100行show4,show5的重复代码");
}
}
接口的应用
- 接口代表规则,是行为的抽象。想要让哪个类拥有一个行为,就让这各类实现对应的接口就可以了。
- 当一个方法的参数是接口时,可以传递接口所有实现类的对象,这种方式称之为接口多态
适配器设计模式
简单理解:设计模式就是各种套路
适配器设计模式:解决接口与接口实现类之间的矛盾问题
当一个接口中抽象方法过多,但是我只要使用其中一部分的时候,就可以用适配器设计模式。
2.书写步骤:
编写中间类xxxAdapter,实现对应的接口
对接口中的抽象方法进行空实现
让真正的实现类继承中间类,并重写需要用的方法
为了避免其他类创建适配器类的对象,中间的适配器类用abstract进行修饰。
内部类
类的五大成员:
属性、方法、构造方法、代码块、内部类
内部类:在一个类的内部再定义一个类,这个类称为内部类
内部类的访问特点:
1.内部类可以直接访问外部类的成员,包括私有
2.外部类要访问内部类的成员,必须创建对象。
什么时候用到内部类?
B类表示的事物是A类的一部分,且B单独存在没有意义。
内部类的分类
成员内部类、静态内部类、局部内部类(前三个了解)和匿名内部类(掌握)。
成员内部类
- 写在成员位置的,属于外部类的成员。
- 成员内部类可以被一些修饰符所修饰,比如:private,默认,protected,public,static等
- 在成员内部类里面,JDK16之前不能定义静态变量,JDK16开始才可以定义静态变量。
获取成员内部类对象
方法一:在外部类中编写方法,对外提供内部类的对象。----当成员内部类被private修饰时
方法二:直接创建格式:--------当成员内部类被非私有修饰时
外部类名.内部类名 对象名=外部类对象.内部类对象
package test07;
public class Out {
String name;
private class Inner{
}
public Inner getInstance(){
return new Inner();
}
}
-----------------------------------------------
package test07;
public class Test {
public static void main(String[] args) {
//是否能用与内部类的权限修饰符有关
// Out.Inner oi=new Out().new Inner();
Out o=new Out();
System.out.println(o.getInstance());
}
}
外部类成员变量与内部类成员变量重名时,在内部类如何访问?
外部类名.this.变量名
静态内部类
静态内部类只能访问外部类中的静态变量和静态方法,如果想要访问非静态的需要创建对象
package test07;
public class Car {
int a=10;
static int b=20;
//静态内部类
static class Inner {
public void show1(){
//要访问a,需要创建对象
Car c=new Car();
System.out.println(c.a);
//b可以直接访问
System.out.println(b);
//System.out.println("非静态方法被调用了");
}
public static void show2(){
//要访问a,需要创建对象
Car c=new Car();
System.out.println(c.a);
//b可以直接访问
System.out.println(b);
//System.out.println("静态方法被调用了");
}
}
}
创建静态内部类对象的格式:外部类.内部类 对象名=new 外部类名.内部类名();
调用非静态方法的格式:先创建对象,用对象调用
调用静态方法的格式:外部类名.内部类名.方法名();
package test07;
public class Car {
int a=10;
static int b=20;
//静态内部类
static class Inner {
public void show1(){
System.out.println("非静态方法被调用了");
}
public static void show2(){
System.out.println("静态方法被调用了");
}
}
}
----------------------------
package test07;
public class Test {
public static void main(String[] args) {
//创建静态内部类的对象
//只要是静态的东西,都可以用类名之间获取
Car.Inner ci=new Car.Inner();
ci.show1();
//静态方法
//用ci.show2()也可以,但是不推荐
Car.Inner.show2();
}
}
局部内部类
- 将内部类定义在方法里面就叫局部内部类,类似于方法里面的局部变量
- 外界是无法直接使用局部内部类,需要在方法内部创建对象并使用
- 该类可以直接访问外部类的成员,也可以访问方法内的局部变量
package test07;
public class Car {
int a=10;
public void show(){
int b=20;
//局部内部类
class Inner{
String name;
int age;
public void method1(){
System.out.println(a);
System.out.println(b);
System.out.println("局部内部类中的method1方法");
}
public static void method2(){
System.out.println("局部内部类中的method2静态方法");
}
}
//创建局部内部类的对象
Inner i=new Inner();
System.out.println(i.age);
System.out.println(i.name);
i.method1();
Inner.method2();
}
}
--------------------------------------------------------------
package test07;
public class Test {
public static void main(String[] args) {
//创建对象,调用show方法
Car c=new Car();
c.show();
}
}
----------------
//输出
0
null
10
20
局部内部类中的method1方法
局部内部类中的method2静态方法
匿名内部类(重要)
匿名内部类本质上就是隐藏了名字的内部类
什么是匿名内部类?
隐藏了名字的内部类,可以写在成员位置,也可以写在局部位置。
格式的细节:
包含了继承或实现关系、方法重写、创建对象。
整体就是一个类的子类对象或者接口的实现对象
使用场景:
当方法的参数是接口或者类时,
以接口为例,可以传递这个接口的实现类对象
如果实现类只要使用一次,就可以用匿名内部类简化代码。
格式:
new 类名或者接口名(){
重写方法;
};
eg:
new Inter(){
public void show(){
}
}
package test07;
public abstract class Animal {
public abstract void eat();
}
--------------------------------
package test07;
public class Dog extends Animal{
@Override
public void eat() {
System.out.println("重写eat抽象方法");
}
}
--------------------------------
package test07;
public class Test {
public static void main(String[] args) {
//在测试类中调用下面的method方法?
//以前:
//要自己写一个子类继承Animal类
//再创建子类的对象,传递给method方法
// Dog d=new Dog();
// method(d);
//如果Dog类我只用一次,那么还需要单独定义一个类太麻烦了。
method(
new Animal() {
@Override
public void eat() {
System.out.println("狗吃骨头");
}
}
);
}
public static void method(Animal a){//Animal a=子类对象 多态
a.eat();//编译看左边,运行看右边
}
}
-------------------------------------------------------------
枚举
-
枚举是一种特殊类
-
枚举类的格式
修饰符 enum 枚举类名{
名称1,名称2;
其他成员;
}
注意:
- 枚举类中的第一行,只能写一些合法的标识符(名称),多个名称用逗号隔开。
- 这些名称,本质是常量,每个常量都会记住枚举类的一个对象。
- 枚举类的第一行只能罗列一些名称,这些名称都是常量,并且每个常量记住的都是枚举类的一个对象。
- 枚举类都是最终类,不可以被继承。
- 枚举类中,从第二行开始,可以定义类的其他各种成员
- 编译器为枚举类新增了几个方法,并且枚举类都是继承:java.lang.Enum类的,从enum类也会继承到一些方法。
- 枚举类的构造器都是私有的(写不写都是私有的),因此,枚举类对外不能创建对象。
阶段项目
事件
事件是可以被组件识别的操作。
当你对组件干了某件事情之后,就会执行对应的代码。
事件源:按钮 图片 窗体.....
事件:某些操作
如:鼠标单击,鼠标划入...
绑定监听:当事件源上发生了某个事件,则执行某段代码
KeyListener MouseListener ActionListener
键盘监听 鼠标监听 动作监听(鼠标左键点击和空格)
特殊类
1.获取随机数
1.导包 import java.util.Random;
导包的动作必须出现在类定义的上边。
2.创建对象---表示要是开始用Random这个类了
Random r=new Random;
上面这个格式里面,只有r是变量名,可以变,其他的都不允许变。
3.生成随机数---真正开始干活了
Int number=r.nextint(随机数的范围);
上面这个格式里面,只有number是变量名,可以变,其他的都不允许变。
判断范围:
在小括号内,书写的是生成随机数的范围,范围是从0开始的,到数-1结束
口诀:包头不包尾,包左不包右
IDEA快捷操作
Ctrl+alt+l 格式化代码,让代码变齐
Ctrl+/ 单行注释或解除注释
Ctrl+shift+/ 多行注释或解除注释
按住鼠标滚轮 或者 按住alt 不松,再拖动,可以同时修改选中的代码
alt+insert 可选constructor设置构造方法和选Getter and Setter 来设置setX,getX
或者安装ptg插件后,右键导入javabean.
Ctrl +alt+v 自动生成左边
对于数组用for循环遍历时,可以用
对一串代码加循环,选中要加循环的代码后按ctrl+alt+t
选住后按shift+f6 批量修改
选中方法,ctrl+b跟进
ctrl+z 撤销操作