java
一. 关键字,标识符,常量
1. 学习了计算机基础知识(软件/硬件)
2. java语言的特点:
面向对象语言的一种
跨平台
开源
3. 了解了java平台版本以及历史.
4. 开发一个Java应用程序
jre:Java程序运行环境,也包括jvm以及java所需的核心类库.
jvm:java虚拟机
jdk:java开发工具包,包含jre以及开发工具的包.
三者之间的关系: jvm<jre<jdk
5. 了解了什么是关键字:
关键字是指被Java语言赋予特定含义的词.
class :表示创建一个类(Java语言最基本的单元)
public:权限修饰符的一种
static:静态修饰符号
void:和java的方法有关
6. 什么是标识符:
针对包,类,接口,方法,变量,常量等起名字的字符序列
标识符的组成:
26个英文字母(大小写)
数字字符
$符号
_下划线符号
.严格区分大小写的
标识符的注意事项:
1.数字字符不能作为标识符的开头位置
2.不能是Java中的关键字
3.Java严格区分大小写,我们在起名字的时候:见名知意
4.满足条件:满足组成的一种即可!不能是非法字符
7. 包,类,接口,方法,变量,常量,书写规则
包: (目录/文件夹) 都是字母小写 或者可以有"_"
类: 如果是一个单词 首字母大写 其余小写 例: class Student{}
如果是多个单词组成 每个单词首字母都大写 其余小写 例: class DataTypeDemo{}
接口: 与 类 相同
方法: 如果是一个单词 字母全部小写 例: main ()
int price = 10;
如果是多个单词 第一个单词全部小写 从第二个单词开始每个单词的首字母大写其余小写
例: checkUserName
int appleprice = 10;
变量: 与 方法 相同
常量: 如果是单个单词 字母全部大写 例:HELLO
如果是多个单词 每个单词字母都大写 单词与单词之间用"_"隔开
8. 什么是常量:
在程序执行过,其值不发生改变的量 分为: 字面值常量 自定义常量
1.字面值常量:
字符串常量:使用双引号包裹起来的内容:称为"字符串常量" "HelloWorld"
字符常量: 使用单引号包裹起来的内容 'a' 'A'
整数常量: 100 56
小数常量: 2.15 0.64
布尔常量: true false
空常量: null
2.自定义常量(面向对象 关键字 final)
进制也属于常量
二. 变量,运算符
1. 了解了更简单的方法: 8421码 可以快速的进行二进制到十进制,十进制到二进制的转换.
2. 有符号位的数据表示法
计算机底层对数据的计算: 是通过补码进行运算的
正数的 原码 反码 补码 相同
负数的最高符号位为1
负数的反码是在原码的基础上,最高符号位不变,数值位按位取反.
负数的补码是在反码的基础上,最高符号位不变,数值位末尾+1.
3. 变量 在程序执行过程中,其值发生改变的量
变量的三要素
数据类型
变量名: 满足标识符规则
初始化值: 满足的范围即可
格式: 数据类型 变量名 = 初始化值
4. 数据类型 :在Java中,数据类型分为两大类型:
A)基本数据类型:四类八种 (研究的都是基本类型)
整数类型:默认int
字节类型 byte 占1个字节(8个比特位) 取值范围:-128~127
短整型 short 占2个字节
整数默认类型 int 整数默认类型 占4个字节
长整型 long 占8个字节
注意事项:必须在long的初始化值的末尾加L或者l
浮点类型:默认类型double
单精度 float 单精度 占4个字节
注意事项:
float f = 12.56F ; //后面加上F或者f
双进度 double 双进度 占8个字节
字符类型 char 占2个字节
初始化值:单引号括起来的单个内容
布尔类型 boolean 不会参与类型转换:仅仅表示真,假 占1个字节
要么是true/要么false
int a = 10 ;
int b =20 ;
比较a与b是否相等:获取到boolean类型的结果
B)引用数据类型:后面说
数组,类,接口
5. 定义变量的注意事项:
在java语言(强类型语言:语法结构很严谨)中,同一个变量不能重复定义
(javascript语言:弱类型语言:可以去重复定义变量)
一行就写一个变量即可! 一行结束之后分号;(代码规范风格)
一行也可以定义多个变量;
变量要么直接初始化,要么先定义,但是必须在使用之前对其进行初始化
变量要进行运算,必须要确定数据类型的一致
在Java中有一个隐式类型转换: byte,short,char三者之间不进行相互转换,
参与运算, 优先转换为int类型,long,float-double类型
6. 显示转换与隐式转换
显示转换(强制转换) : 大的数据类型----->小的数据类型
格式: 目标数据类型 变量名 = (目标数据类型)初始化值; 会有损精度!
隐式转换:(隐式类型提升) byte,char,short三者之间不转换,一旦参与运算,优先提升为int...
超出了 byte类型 的范围为-128~127
先算出int 类型的二进制(4字节) 然后化为byte(1字节) 类型的二进制
最高符号为0,原码 ,反码,补码都相同
最高符号为1 数值位-1 求反码 数值位按位取反求原码
7. Java中的运算符号:
(1) 算术运算符 + - * / %
扩展算术运算符 ++ --
第一种:
++或者--单独使用
无论++或者--在数据前面还是数据后:都是对当前数据本身自增1或者自减1
第二种:
++或者--参与运算使用
如果++或者--在数据的前面:需要先进行自增1或者自减1,然后再参与运算!
如果++或者--在数据的后面:先进行运算,然后再进行自增1或者自减1
(2) 赋值运算符 =
扩展的赋值运算符:将符号右边的数据和左边的数据相加,然后再赋值给左边的这个变量
+=,-=,*=,/=,%=
+=举例:
int a = 10 ;
a += 20 ;
类似于 a = a + 20 ;
举例:
short s = 1;
1)s = s + 1 ;
2)s+=1 ;
以上代码1),2)哪一句会编译失败?为什么?哪一句编译成功?
1)编译失败
byte,short,char三者不转换,一旦参与运算,先提升为int类型,然后再参与运算!
2)编译成功:
s+= 1 ; 类似于s = s + 1 ;
扩展的赋值运算符中:
特点:隐藏了强转类型转换
等价于 s = (short)(s+1) ;
8. 关系(比较)运算符
=,<,<=,>=,>,==
无论我们的表达式是简单还是复杂的,最终比较运算符的结果不是true,就是false
注意: ==不能写成=
数学表达式:
3 <=x <=5 x>=3 && x<=5 Java语言(逻辑符号)
9. 逻辑运算符
基本的逻辑运算符号:
逻辑单与: & 并列关系(满足全部条件) 有false,则false
逻辑单或: | 或的关系:满足一个条件即可 有true,则true
逻辑异或: ^ 相同则为false,不同则为true
逻辑非: ! 非true,则false;非false则true 偶数个非是他本身
扩展的逻辑运算符:
逻辑双与: && 左边有false,右边则不执行
逻辑双或: || 左边有true,右边则不执行
10. 位运算符
基本的位运算符号:
位与: & 有0则0
位或: | 有1则1
位异或: ^ 相同则为0 不同则为1
特点: 一个数据被另一个数据位异或两次,其值是他本身!
位运算之位移符号:
<<: 左移
将数据的补码进行左移动,右边不够的补0;将最高符位丢弃掉
>>: 右移
将数据的补码进行右移动;如果最高符号位为1,则左边补1;
最高符号位为0,则左边补0;
>>>: 无符号右移
无论最高符号位是1还是0,左边始终补0
左移的特点: <<:将左边的数据乘以2的移动次幂
右移的特点: >>:将左边的数据除以2的移动次幂
11. 三元(三目)运算符
int temp = (x > y )? x: y ;
int result = (temp > z)? temp : z ;
或者
int max2 = (x>y)?((x>z)?x:z):((y>z)?y:z) ;
三. 语句
1. 键盘录入
使用步骤
(1). 导包: 在java语言中:只要不是java.lang包下的类都需要导入!
位置:在class上面
import java.util.Scanner;
(2). 固定格式: 创建键盘录入对象(文本扫描器对象)
Scanner 对象名 = new Scanner(System.in) ;
(3). 开始录入数据 :使用int类型举例
int 变量名 = 对象名.nextInt();
import java.util.Scanner;
class LiXin6{
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
System.out.println("请输入第一个值");
int a = sc.nextInt();
System.out.println("请输入第二个值");
int b = sc.nextInt();
System.out.println("请输入第三个值");
int c = sc.nextInt();
int max2 = (a>b)?((a>c)?a:c):((b>c)?b:c);
System.out.println("最大值为:"+max2);
}
}
public String nextLine():正式用法:
import java.util.Scanner;
class ScannerDemo2{
public static void main(String[] args){
//创建键盘录入对象
Scanner sc = new Scanner(System.in) ;
//提示并录入数据
System.out.println("请输入一个字符串数据:") ;
String line = sc.nextLine() ;
System.out.println("您输入的字符串是:"+line) ; //"helloworld"
}
}
如果同时录入两个int类型,
同时录入两个String类型
或者 先录入String,在录入int
先录入int,在录入String:哪一个会有问题?
(4). 键盘录入的细节:
如果先录入int,再录入String会出现,会漏掉第二个数据String
原因就是 输入回车符号-->才能录入数据 ;回车符号---> (换行)
方案1:在录入字符串之前,新创建一个键盘录入对象
//先录入int,在录入String字符串
Scanner sc = new Scanner(System.in) ;
System.out.println("请输入第一个数据:") ;
int a = sc.nextInt() ;
//创建一个新的键盘录入
Scanner sc2 = new Scanner(System.in) ;
System.out.println("请输入第二个数据:") ;
String b = sc2.nextLine() ;
方案2:Scanner类提供了这个功能:
public String next():录入一个字符串 (非正式用法)
System.out.println("请输入第二个数据:") ;
String b = sc.next() ;
2. if 语句
格式一:
if(表达式){
语句;
}
格式二:
if(表达式){
语句1;
}else{
语句2;
}
if 语句的嵌套:
if(表达式1){
if(表达式2){
语句1;
}else{
语句2;
}
}else{
if(表达式3){
语句3;
}else{
语句4;
}
}
if 语句格式三 :
if(表达式1){
语句1;
}else if(表达式2){
语句2;
...
...
...
}else{
语句n;
}
3. switch语句
switch语句格式:
switch(表达式){
case 值1:
语句1;
break ;
case 值2:
语句2;
break ;
...
...
default:
语句n;
break ;
}
switch语句使用的注意事项:
(1). case语句后面的值只能是常量,不能是变量(Java是一个强类型语言的:语法结构非常严谨)
(2). 书写switch语句的时候,case语句必须存在break语句,结束switch语句的! 如果没有书写break语句,会造成"case穿透!"现象
(3). switch语句的结束条件
a)遇见break结束
b)程序默认执行末尾结束
4. for 语句 (明确循环次数使用)
for的格式:
for(初始化语句;条件表达式;控制体语句;){
循环体语句;
}
for 语句的嵌套:
for(初始化语句;条件表达式;控制提语句){
for(初始化语句;条件表达式;控制体语句){
}
}
5. while 语句 (不明确循环次数使用)
while语句的格式:
初始化语句;
while(条件表达式);
循环体语句;
控制体语句;
使用的场景不同
6. 死循环 break可跳出死循环
Kxxxxxxxxxx 死循环的格式有两种: 1. for(;;){ 循环体语句; } 2. while(true){ 循环体语句; }
7. do while 循环语句
do while循环语句的格式:
do{
循环体语句;
控制体语句;
}
while(条件表达式);
8. for while 和 do while的区别
1.格式的不同
2.for循环节省内存空间:
for循环结束,变量随着被释放掉,节省内存空间;(不能访问这个变量了.)
while循环结束,依然可以访问这个变量,比较消耗内存空间...
3.dowhile:优先循环体语句,即使条件不成立,循环体至少执行一次
开发中:
优先for,其次while,再次do-while
9. 跳转控制语句有三个关键字 :
break: 结束中断,结束循环(不能单独使用) 在switch和循环中使用
continue: 继续, 在循环中使用 ,结束当前循环,立即进入下一次循环
return:很少单独使用,结合有具体返回值类型的方法使用! 结束方法的;
看程序:写结果
for(int i = 1; i <= 10; i++) { //i=1,i=2,i=3,i=4,i=5,i=6....i=9
if (i % 3 == 0) {
//在此处填写代码
}
System.out.println("java基础班");
//1)2),3),4)
}
在控制台输出2次“java基础班” break;结束中断
在控制台输出7次“java基础班” continue:结束当前循环,立即进入下一次循环
在控制台输出13次“java基础班” System.out.println("java基础班");
四. 方法
1. 方法:就是使用{}代码块包起来,并且起一个名字(见名知意)
Java中定义方法的格式:
(1).有具体返回值类型的方法的定义
固定格式
public static 返回值类型 方法名(小驼峰命名法)(参数类型1 变量名1,参数类型2 变量名2....){
int a,int b,intc
...
return 结果;
}
定义两个数据之和的功能时候,
两个明确
1)明确返回值类型:int
2)明确参数类型以及参数个数
int类型 2个参数
public static int sum(int a,int b){//形式参数
int result = a + b;//30+20
return result ;
}
}
例: class Text {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("请输入第一个值");
int a = sc.nextInt();
System.out.println("请输入第二个值");
int b = sc.nextInt();
System.out.println("请输入第三个值");
int c = sc.nextInt();
int max = sum(a, b, c);
System.out.println(max);
}
public static int sum(int a, int b, int c) {
int max = (a > b) ? ((a > c) ? a : c) : ((b > c) ? b : c);
return max;
}
}
2. 方法使用中的注意事项
(1). 方法和方法是平级关系,不能进行嵌套: 在一个方法中定义另一个方法不允许
(2). 在Java中,定义方法的时候形式参数必须携带数据类型! (Java是一个强类型语言)
(3). 调用方法的时候,传递的实际参数不需要在携带数据类型了
(4). 定义方法的时候: 有{括号的地方不能有分号;
没有具体返回值的类型的方法的定义:
没有具体返回值类型的方法调用
1)单独调用: 只能单独调用
2)输出调用:
3)赋值调用:
//void v = printStar() ; //FunctionDemo.java:28: 错误: 非法的表达式开始
//输出调用
//System.out.println(printStar()) ; 不行
//单独调用
//printStar(m,n) ;
3. 方法重载 :
方法重载(overload) :方法名相同,参数列表不同,与返回值无关!
参数列表不同:
1)参数个数不同
2)参数类型不同
五. 数组
1. 数组 : 就是存储多个数据的容器,必须保证容器内数据类型的一致.
2.数组的定义格式:
动态初始化 :
给定了数组的长度,系统默认对元素进行初始化!
数据类型 数组名称[] = new 数据类型[数组长度];
数组类型 []数组名称 = new 数据类型[数组长度];
例: int[] arr ;定义一个int类型的数组arr
int[] arr = new int[3] ;
int arr[];定义了一个int类型的arr数组
int arr[] = new int[3] ;
length : 获取数组长度.
静态初始化 :
我们给定的具体的元素,数组长度由系统确定
数据类型 数组名称[] = new 数据类型{元素 1, 元素 2, ....};
数据类型 []数组名称 = new 数据类型{元素 1, 元素 2,....};
可简写为 : 数据类型 数组名称[] = {元素 1, 元素 2,.... };
数据类型 []数组名称 = {元素 1, 元素 2,....};
3. 遍历
printArray2(arr) ; //调用方法
public static void printArray2(int[] arr){
System.out.print("[") ;
//遍历数组
for(int x = 0 ; x < arr.length ; x ++){
//判断:如果当前x :取到最大索引值 arr.length-1
if(x==arr.length-1){
System.out.println(arr[x]+"]") ;
}else{
//不是最后一个索引值,中间的元素 arr[x]+", " 不换行
System.out.print(arr[x]+", ") ;
}
}
}
// 栈:存储都是局部变量(在方法定义中或者方法声明上)
// 堆:new出来的东西,创建对象 (里面存储:"成员变量")
// 方法区:有哪些方法--分别存储在哪个类中---xxx.class()
4. 数组的基本应用 :
求最值问题:
class Text {
public static void main(String[]args) {
int[] arr = {69,13,56,87,24} ;
//调用方法
int result = getMax(arr);
System.out.println("数组中的最大值是:" + result);
}
public static int getMax(int[] arr){
//假设思想:
int max = arr[0] ;
for(int x = 1 ; x < arr.length ; x ++){
//判断
if(arr[x] > max){
max = arr[x] ;
}
}
return max ;
}
}
5. 冒泡排序:
//冒泡:两两比较,较大的值往后放,第一次比较完毕,最大值出现在最大索引处;总共比较的次数:数组长度-1次
class Text {
public static void main(String[] args){
int arr[] = {12,24,6,35,21};
for (int x = 0;x < arr.length-1;x++){
for (int y = 0;y < arr.length-1-x;y++){
if (arr[y] > arr[y+1]){
int a = arr[y];
arr[y] = arr[y+1];
arr[y+1] = a;
}
}
}
sum (arr);
}
public static void sum(int arr[]){
System.out.print("[");
for (int x = 0; x < arr.length;x++){
if (x == arr.length-1){
System.out.print(arr[x]+"]");
}else{
System.out.print(arr[x]+",");
}
}
}
}
6. 方法的形式参数问题 :
形式参数的改变不能影响实际参数
7. 类与对象的关系 :
类 : 能够描述现实世界真实事物的一组属性和行为的集合!
事物 : 现实真是存在的事物;
创建对象 : 格式:类名 对象名 = new 类名();
面向对象 :
面向对象的思想特点:
1)更符号我们生活中是思想行为习惯
2)让复杂的事情简单化
3)我们从执行者变成了指挥者
三大特点 : 封装,继承,多态
8. 成员变量和局部变量的区别 :
1)在程序中的书写位置不同
局部变量:
方法定义中或者方法声明上
成员变量:
在类中,成员方法外定义的变量
2)在内存中
局部变量:
在栈内存中
成员变量:
在堆内存中
3)生命周期不同
局部变量:
随着方法调用而存在,随着方法调用完毕而消失!
成员变量:
随着对象的创建而存在,随着对象创建完毕之后,不会立即消失,
需要等待GC(垃圾回收器空闲时候回收掉!)
GC算法----->标记算法
标记---清除
4)初始化不同
局部变量:
可以先定义,但是必须在使用之前必须赋值,否则:可能尚未初始化变量
成员变量:
可以不初始化,它存在系统默认初始化!(根据类型判定)
如果一个方法的形式参数是引用类型 是具体类,那么调用该方法时,实际参数如何传递
//学生类
class Student{
//有一个成员方法:学习的方法
public void study(){
System.out.println("Good Good Study ,Day Day Up!!") ;
}
}
//定义一个StudentDemo类
class StudentDemo{
//有一个method成员方法
public void method(Student s){ //方法的形式参数是Student类型
//调用method 方法的时候:实际参数需要传递的是当前类的具体对象
//Student s = new Student();
s.study() ; //对象名.方法() ; //stu.study() ;
}
}
//测试类
class StudentTest{
public static void main(String[] args){
//在测试类中访问StudentDemo类中的method方法?
//创建StudentDemo类对象
StudentDemo sd = new StudentDemo() ;
//sd.method(s) ;//找不到符号
//先去创建学生对象
Student stu = new Student() ;
sd.method(stu) ;
}
}
9. 匿名对象
没有名字的对象
格式:
new 类名() ;
匿名对象有一个特点:可以作为参数进行传递
在开发中,匿名对象使用一次即可!
(因为没有栈内存变量指向堆内存地址,直接是在堆内存开辟空间,使用完毕,立即被回收!)
class NoNameObjectDemo{
public static void main(String[] args){
//之前的写法
//访问StudentDemo类中的method 方法
//创建StudentDemo类对象
StudentDemo sd = new StudentDemo() ;
//创建一个具体的学生对象
Student s = new Student() ;
sd.method(s) ;
System.out.println("------------------------------") ;
//方式2
StudentDemo sd2 = new StudentDemo() ;
sd2.method(new Student()) ;
System.out.println("------------------------------") ;
//链式编程
//一步走
new StudentDemo().method(new Student()) ;
}
}
10. 封装
目的 : 保证数据的安全性
11. private关键字的特点
1)可以修饰成员变量,也可以修饰成员方法,但是都只能在本类访问,外界类不能够访问
2)这些被私有修饰的成员变量,或者成员方法,可以间接通过公共方法来访问!
12. this
this:解决局部变量隐藏了成员变量
格式 : this.成员变量名 = 局部变量;
this:就是代表当前类的对象的地址值引用!
this.变量名 :访问的本类的成员变量
this.方法名():访问的是本类的成员方法
this() ; 访问本类无参构造方法
this(String xx):访问本类的有参构造方法
13. 构造方法
1)构造方法名和类名一致
2)没有具体的返回值类型
3)连void都没有
构造方法的目的:为了给类的成员的一些数据进行初始化
无参构造方法 :
private String brand ;
private int price ;//价格
private String color ;
public Phone(){
System.out.println("这是phone类的无参构造方法...") ;
}
....
....
Phone p = new Phone();//
//setXXX()赋值
p.setBrand("锤子手机") ;
p.setPrice(1299) ;
p.setColor("黑色") ;
System.out.println("品牌:"+p.getBrand()+",价格:"+p.getPrice()+",颜色:"+p.getColor()) ;
System.out.println(p) ;
有参构造方法 :
public Student(String name){
//this.name = name ;
System.out.println("这是Student类带String类型的有参构造方法...") ;
}
.... (set xxx,get xxx)
....
Phone p2 = new Phone("锤子手机",1299,"黑色") ;
System.out.println("品牌:"+p2.getBrand()+",价格:"+p2.getPrice()+",颜色:"+p2.getColor()) ;
}
一个类的成员:
1)成员变量
2)成员方法
3)构造方法
14. 静态static关键字的特点:
1)随着类的加载而加载
2)优先于对象存在: 它不能this共存 (this:代表当期类对象的地址值引用)
对象还没有new的时候,当前被static修饰的成员就已经内存了
3)被静态修饰的 可以被多个对象共享:有共享共用的意思
4)被静态修饰的变量,方法----->静态变量或者静态方法
我们所说的成员变量和成员方法:都指的是非静态
静态的成员的访问方式:类名.变量
类名.方法名()
关于static关键字的使用注意事项:
1)非静态的方法既可以访问静态变量,也可以访问非静态的变量
既可以调用静态方法,也可以调用非静态方法
2)静态的方法:只能访问静态变量,
只能调用静态方法
简单记:静态只能访问静态
15. 代码块
在java中用{}包起来的内容,称为代码块.
分类 :
局部代码块 : 在方法定义中使用,作用:限定局部变量的生命周期.
构造代码块 : 在类的成员位置(类中,方法外),使用使用{}包裹起来
作用:给类中的一些成员进行数据初始化
特点:每次在执行构造方法之前,如果存在构造代码块,先执行构造代码块中的内容!
静态代码块 : 在类的成员位置,直接使用 static{}. 静态代码块就加载一次!
作用:也可以通过static代码块,对一些操作(后期IO流创建文件/JDBC)
特点:随着类的加载而加载,优先于对象存在!
// 优先级:
// 静态代码块(只执行一次) > 构造代码块 > 构造方法
16. 继承
将多个类的共性内容抽取到一个独立的类中,然后这多个类和独立的这个类产生一种关系 : 继承关系
关键字 : extends
书写格式 :class Fu{}
class Zi extends Fu{}
继承的好处:
1)提高代码的维护性
2)提高代码的复用性
3)让类和类之间产生的关系,是"多态的前提条件"
继承的特点 :
1)类与类之间的关系,继承关系,只支持单继承
2)不支持多继承,但是可以支持多层继承
继承中使用的注意事项 :
1)子类继承父类 :可以继承父类的非私有的成员,私有的成员外界不能访问的,只能在本类中访问, 但是可以通过公共方法间接访问.
2)构造方法是不能被继承的,但是子类可以间接通过 super 关键字访问父类的构造方法.
一个类的组成 :
成员变量
构造方法
成员方法
继承中,每一个成员变量的关系问题
成员变量 :
a)子类继承父类,如果子类中的成员变量名称和父类的成员变量名称不一致,分别访问即可!
b)子类继承父类,如果子类的成员变量名称和父类的成员变量名称一致:如何访问呢? (重点)
1)首先在子类的局部位置找,是否存在局部变量名称,如果有,就使用
2)如果没有,就在子类的成员位置找,是否存在这个变量,如果存在,就使用
3)如果在子类的成员位置中没有找到,直接在父类的成员位置中找,如果有,就是使用!
4)如果父类的成员位置都没有,就没有这个变量,报错!
// 遵循一个原则:就近原则!
继承中构造方法的访问 :
a)子类继承父类,子类的所有的构造方法都会默认的访问父类的无参方法.
子类的所有构造方法的第一句话:默认隐藏了super() ;
因为子类中肯能会使用到父类的数据,所以在继承关系中,
得先让父类初始化---->构造方法 : 分层初始化!(先父类无参构造方法,在执行子类的构造方法)
super:代表的父类对象的空间表示(父类对象的地址值引用!)
b)如果父类中的无参构造方法没有,子类会怎么样?
子类的所有的构造都会报错! (因为子类所有构造方法默认父类的无参构造方法!)
如何解决呢?
方式1:手动给出父类的无参构造方法(推荐)
方式2:在子类的构造方法中的第一句话:通过super(xxx),间接的访问父类的有参构造方法
方式3:只要子类的所有构造方法中一个能够让父类初始化即可!
在子类的有参构造方法中:this():---->访问本类的无参构造方法,然后再子类的无参构造方法中
间接访问父类的有参构造方法super(xxx) ;
如何正确使用继承关系(extends)
如果一个A类是B类的一种,或者B类是A类的一种,这个时候就可以使用继承关系
继承关系:现实世界事物中本质体现的是一种 "is a"的关系
17. 总结:this和super 的区别
this:代表的当前类对象的地址值引用
super:代表的父类对象的地址值引用(代表父类的空间标识)
访问成员变量
this.变量名; 访问的本类中的成员变量
super.变量名; 访问的是父类的成员变量
访问构造方法:
this() ; 访问本类的无参构造方法
super() ;访问的父类的无参构造方法
this(xxx);访问的本类的有参构造方法
super(xxx);访问的父类的有参构造方法
成员方法:
this.方法名();访问的是本类的成员方法
super.方法名() ;访问的是父类的成员方法
18.方法重载,方法重写
//如果子类出现了和父类一模一样的方法声明,叫做方法重写!(Override) —方法复写(覆盖)
//方法重写和方法重载的区别?
方法重载:Overload
在一个类中,提供n多个功能,这些功能,方法名相同,参数列表不同,与返回值无关(目的:提高某个功能的扩展性)
参数列表不同:
1)类型不同
2)个数不同
3)考虑参数类型的顺序
public static void open(int a,double d){}
public static void open(double a,int b){}
构造方法也可以重载!
重载的目的:为了提高功能的扩展性:同一个方法可以接收很多类型的参数
方法重写:Override
在继承关系中,子类出现了父类一模一样的方法声明,重写的目的:子类有自己的功能,需要将父类的该功能覆盖掉!
重写的目的:为了沿用父类的功能,并且还需要使用子类的功能(具体的子类才具备具体的动作...)
举例:
动物:
都具备吃和睡的功能
猫和狗都继承自动物类,他们吃的不一样的
猫和狗就需要讲吃和睡的功能覆盖掉...
猫具体吃鱼
狗具体吃肉
19.关键子 : final
final(状态修饰符):最终的,无法更改的
关于final关键字的特点:
1)可以修饰类,该类不能被继承!
2)可以修饰符成员方法,成员方法不能重写! (根据具体的题意要求!)
3)可以修饰的变量,这个变量此时是一个常量! (自定义常量)
final修饰基本数据类型和引用类型的区别?
final修饰基本数据类型: 基本数据类型的对应的数据值不能在被赋值了,只能赋值一次!
final修饰引用类型:引用数据类型对应的地址值不能被改变
final Student s = new Student() ;//修饰实例变量s,s的堆内存地址值永远是固定值!
s = new Student() ;//重新开辟空间(报错)
六.多态
1.多态 : 一个事物在不同时刻不同形态.
多态的前提条件:
1)必须存在继承关系 (extends)
2)必须存在方法重写
子类需要覆盖父类的功能
Animal
eat():"动物都需要吃饭..."
Cat
eat() "猫吃鱼"
Dog
eat() "狗吃骨头"
3)必须有父类引用指向子类对象
class Fu{}
class Zi extends Fu{
//存在重写
}
格式: Fu fu = new Zi() ;
2. 多态成员的访问特点
Fu f = new Zi() ;
成员变量:编译看左(看Fu类是否存在变量,存在,编译不会报错!)
运行看左(使用Fu类的东西)
成员方法:(一般没有明确是静态方法的都是----->非静态)
编译看左(看Fu类是否存在这个方法,存在,编译不会报错!)
运行看右(存在方法重写,所以最终子类的功能将父类的该功能进行覆盖!)
静态的方法:
编译看左看Fu类是否存在这个静态方法,存在,编译不会报错!),
运行看左(静态方法:子类出现了父类一模一样的静态方法,算不上重写,跟类相关的-->类成员)
静态功能推荐的方式:类名.访问
构造方法:
即使多态的情况进行测试,多态的前提条件---->继承关系
当前执行子类的构造方法之前,需要让父类的先进行初始化,然后子类进行初始化(分层初始化!)
3. 多态的好处
1)提高代码的复用性:由继承保证
2)提高了代码的扩展性:由多态保证 (重点)
Fu fu = new Zi() ; 父类引用可以指向子类对象
4. 多态的弊端:
不能访问子类的特有功能 (Fu f = new Zi())
f.方法名() ;报错了. 父类中没有子类特有功能!
如何解决多态的弊端?
方案1: (不推荐)
具体的子类创建具体的子类对象 Zi z = new Zi() ;
z.成员方法名() ;
本身Fu f = new Zi() ;已经在堆内存中开辟空间了
Zi z = new Zi() ;在堆内存中又开辟空间,从内存角度考虑,这种比较消耗内存空间,不太好!
方案2:(推荐使用:"向下转型")
多态的第三个前提条件:父类 引用指向子类对象 :"向上转型 "Fu f = new Zi() ;
能不能将父类的引用转换成子类的引用? 好处:不需要在堆内存开辟空间
可以------>"向下转型"
Zi z = (Zi)f ; 还原成子类型
强转类型转换: 目标类型 变量名 =(目标类型)初始化值;
基本类型 : int num = 65 ;
//num--->char类型
char ch = (char)num ; ====>'A'
5. 多态的向上转型和向下转型
多态的向上转型:多态的第三个前提条件--->父类引用指向子类对象
格式:Fu fu = new Zi() ;
多态的弊端:不能访问子类的特有功能
可以使用向下转型:
将父类的强转强转转换为子类引用
Zi zi = (Zi)fu;
多态的方式:使用向下转型时,可能出现异常?
要使用向下转型,前提必须有父类引用指向子类对象 Fu f = new Zi() ;
遵循向下转型的格式:
Zi z = (Zi)f; 必须心里清楚堆内存存储的类型....
向下转型使用不当,就出现java.lang.ClassCastException:类转换异常: (属于运行时期异常)
当前堆内存中的实例不是该类型时,就会出现问题!
6. 抽象类
什么是抽象类----->现实世界事物中,某个事物是比较概括性(人/水果/动物),描述为抽象事物,
只有具体的工人/苹果/猫或者狗,才具备具体的功能;
将某个事物中的一些功能仅仅给出声明即可,没有方法体----->抽象方法---->此时这个类必须为抽象类!
举例:
动物都需要吃和睡
只要看到具体的动物类:猫类/狗类,才具备吃和睡的功能
将动物类中的吃和睡给出一个声明:加入一个关键字 abstract:抽象方法
动物类----->抽象类
抽象的关键字:Java语言 :abstract关键字 (抽象的含义)
抽象方法的格式;
权限修饰符(一般情况都是public) abstract 返回值类型 方法名(形式参数列表) ;
抽象类的格式:
abstract class 类名{}
7. 抽象类的特点
1)有抽象方法的类一定是抽象类
2)抽象类中不一定只有抽象方法 ,还可以非抽象方法(有方法体)
3)抽象类不能实例化---->意思:不能创建对象
如何实例化呢:通过具体的子类进行实例化(进行对象的创建), 抽象类多态 Fu fu = new Zi() ;Fu类型 抽象类型
4)抽象类的子类有两种情况:
a)目前来说:如果抽象类的子类都是抽象类---毫无意义 因为子类也不能new ,除非再有具体的子类
b)抽象类的子类具体类---才能new :抽象多态的形式 Fu fu = new Zi() ;
抽象类的核心宗旨:就是强制子类必须完成的事情(要将父类中的所有的抽象方法必须重写,否则报错!)
抽象类成员特点:
成员变量
既可以定义变量,也可以常量:被final修饰
成员方法
既可以定义为抽象方法,也可以定义为非抽象方法
如果定义为抽象方法:关键字abstract(显示给出)
构造方法
存在无参构造/有参构造方法---->目的:分层初始化
一个类中没有抽象方法,那么将这个类定义为抽象类的意义何在?
意义:为了不让它直接实例化!
如何实例化:
情况1)直接就有具体的子类
情况2)间接的有具体的子类
8.接口
接口---->它的本质就是体现一个现实世界事物所具有的的额外的扩展功能!
定义格式: interface 接口名{} ------>接口名遵循"标识符规则"---->大驼峰命名法
接口中的方法:不能有方法体,隐藏public abstract关键字,只能是抽象方法,不能有方法体
9. 接口的特点
1)不能实例化(不能创建对象)
2)如何实例化
接口实例化: 通过接口的子实现类(一定是具体类)进行实例化----接口多态(使用时最多的!)
子实现类和接口的关系: implements 实现关系
接口的子实现类如果是抽象类----->肯定要存在抽象类的具体的子类,否则都不能实例化!
接口的子实现类的命名规则:
开发中--->在接口名的后面+Impl:子实现类
interface Inter{}
class InterImpl implements Inter{
}
接口的成员特点:
1)接口中的成员方法:只能是抽象方法,默认的修饰符:public abstract(可以省略不写)
2)接口没有构造方法
3)接口的成员变量只能是常量:
存在默认修饰符:public static final (可以省略不写)
类与类之间的关系: extends 继承关系
只支持单继承,不支持多继承,但是可以多层继承
类和接口的关系: implements关系:实现关系
一个类继承另一个类的同时,可以实现多个接口,中间逗号给隔开
接口与接口之间: extends:继承关系
不仅支持单继承,也可以多继承,中间使用逗号隔开
10.形式参数问题的研究:引用类型
如果方法的形式参数是类 ,调用方法的时候,如何传递实际参数?
具体类,调用该方法,实际参数需要传递当前具体类的对象
抽象类,调用该方法实际参数需要传递的抽象类的子类对象 (抽象类多态)
接口 调用该方式,实际参数需要传递的是当前接口的子实现类对象(接口多态)
如果一个方法的返回值是引用类型,最终方法结束,如何返回?
具体类 :方法返回的就是当前具体类对象!
抽象类 :需要返回的是抽象类的子类对象
接口 :需要返回的是该接口的子实现类对象
11.关键词 : package
包的真实含义:
以后要代码分层...
将包进行划分
开发中,写包名的时候(字母都是小写,多级包) :公司域名反写
开发中:
先按照模块划分,在按照功能划分
用户模块
注册功能
登录功能
用户激活功能(使用邮件激活技术,手机短信验证,微信二维码)
用户退出
商品模块
订单模块
购物车模块
支付模块
12.权限修饰符
默认修饰符
私有修饰符:private
受保护的 :protected
公共的,公开的:public
修饰的权限从小到:private,默认,protected,public
七. 内部类
1. 内部类
在一个类中可以定义另一个类:
在类A 中定义了类B,将类B就称为类A的内部类,类A就是外部类!
成员内部类:
在一个类的成员位置中定义了另一个类
内部类可以访问外部类的成员,包括私有!
外部类如何直接访问内部类的成员方法?
格式:
外部类名.内部类名 对象名 = 外部类对象.内部类对象;
成员内部类的修饰符:
在成员内部类上面---加入private修饰:为了数据的安全性,它的访问---就要外部类的公共访问间接访问...
如果当前成员内部类是静态的, 里面的方法无论是静态的还是非静态的,都只能访问外部类的静态成员,包括私有!
如何直接访问静态成员内部类的成员呢?
将静态的成员内部类看成是外部类的静态成员访问
直接访问方式
外部类名.内部类名 对象名 = new 外部类名.内部类名() ;
2. 局部类部类
关于局部内部类,它的书写位置,在外部类的成员方法中的定义的类
局部内部类可以访问外部类的成员变量包括私有!
在外部类的局部位置,访问内部类的成员方法,创建当前局部内部类对象来访问!
3. 局部内部类访问局部变量的时候,此时局部变量应该注意什么?
(JDK7/JDK8),为什么要加入final关键字呢?
如何此时Java环境是Jdk7,局部内部类访问局部变量时,此时该变量必须显示加入final修饰
目前环境是JDK8环境,做了什么优化?
通过反编译查看
class Outer2$1Inner2{
final int val$num; num已经加入了final修饰
final Outer2 this$0;
public void show(){
System.out.println(val$num);
}
Outer2$1Inner2(){
this.this$0 = this$0;
val$num = I.this;
super();
}
}
原因:
局部变量的生命周期是随着方法调用而存在,随着方法调用结束而消失
而当前外部类对象调用method 方法的时候,此时num进入栈内存,在局部位置创建了局部内部类对象
而局部内部类对象调用它的成员方法访问该变量,方法method方法结束之后,内部类对象不会立即消失,
它里面的成员方法在访问局部变量,局部变量必须变成常量,常驻内存,否则如果当前变量消失了,局部内部类的成员依然在访问
就会出现冲突! 所以 jdk7 收到必须加入final修饰,jdk8通过jvm已经做了优化了,无需手动加入final修饰
4. 匿名内部类
没有名字的内部类 一般在我们局部位置使用!
格式:
匿名内部类它是内部类的一种简化格式
new 类名(可以是抽象类,也可以具体类)或者是接口名(){
重写功能
} ;
匿名内部类的本质:
继承了该类或者是实现了该接口的子类对象
关于匿名内部类在开发中的使用:
// 方法的形式参数如果是一个抽象类,那么实际参数可以需要接口的子类对象
1)将子类定义出来 继承自抽象类
2)直接使用抽象类的匿名内部类
// 方法的形式参数如果是一个接口,实际需要传递的接口子实现类对象
方式1:将接口的子实现类定义出来
方式2;使用接口的匿名内部类
//看程序,写结果
要求:需要在控制台分别打印30,20,10
考点:
外部类直接访问非静态的成员内部类的格式
外部类的成员变量的方法方式,(在成员内部类的成员方法中)
成员变量,局部变量名称都一样(就近原则)
外部类和内部类没有继承关系
class Outer{
int num = 10 ;
//成员内部类
class Inner{
int num = 20 ;
public void show(){
int num = 30;
//补全代码
System.out.println(num);
System.out.println(this.num);//this限定 :this.变量名:当前类的成员变量
// System.out.println(new Outer().num) ; //方式1:new Outer().num
System.out.println(Outer.this.num) ; //方式2:外部类的this限定
}
}
}
public class OuterTest {
public static void main(String[] args) {
Outer.Inner oi = new Outer().new Inner() ;
oi.show();
}
}
// 方法的返回值是一个抽象类?
// 需要返回的是当前抽象类的子类对象
// 方法的返回值是接口类型,需要返回的当前接口的子实现类对象
5. java.lang.Object:是类结构层次的根类(超类—>父类),所有的类都默认继承自Object子类(派生类)
使用JDK提供的API文档学习常用类中的常用功能
API:Application Programming Interface:应用程序接口开发文档
Object功能类的getClass()方法
public final Class getClass():表示正在运行的类 (就是字节码文件对象)
Class----->反射的时候去使用
Class类:
功能:
public String getName(): 获取当前类的全限定名称(包名.类名)
Object类中的getClass()/finalize()/hashCode()以及以后常用类
功能中如果native关键字:本地方法,非java语言底层实现另外一个功能
public int hashCode():(了解)获取对象的一个哈希码值 (本质不是地址值,可以把它理解为地址值)----跟哈希表有关系(HashMap)
一般情况:不同的对象获取的哈希码值是不同的 ,(但是中文字符,可能内容不一样,但是哈希码值不同!)
底层是通过哈希表算出来的.
6. 获取一个类的字节码文件对象有几种方式? 三种
第一种:通过Object类的getClass()--->Class :正在运行的java类: class 包名.类名
第二种:任意Java类型的class属性----获取当前类的字节码文件对象Class
第三种方式:Class里面forName("类的全限定名称(包名.类名)") ; (使用最多)
7. Object的public String toString()
返回对象的字符串表示形式。结果应该是一个简明扼要的表达,容易让人阅读。
建议所有子类覆盖此方法。
描述一个对象:是由很多属性(成员变量组成),应该看到的具体的属性描述
要么手动方式(不推荐)
也可以直接快捷键----重写toString即可
大部分的常用类或者后面的集合都会重写Object类的toString()
8. Object类的equals方法
public boolean equals(Object obj)
判断当前obj对象是否和当前对象想等
面试题:
equals和==的区别?
==: 连接的基本数据类型: 比较的是数据值否相同
==: 连接的是引用类型: 比较的是地址值是否相同
equals方法:如果使用Object默认的:底层用==,默认比较的还是两个对象的地址值是否相同,
Student s1 = new Student("文章",35) ;
Student s2 = new Student("文章",35) ;
s1和s2虽然地址值不同,他们的成员的内容相同,认为他是同一个人,但是如何让s1.equals(s2)为true:针对equals来说比较的是 成员信息内容是否相同;
重写Object的equals方法同时还需要重写hashCode内容相同,还需要比较哈希码值相同
alt+ins--->hashcode+equals方法
重写之后,就比较的是成员信息的内容是否相同!
克隆方法:
protected Object clone() throws CloneNotSupportedException:创建对象并返回该对象的副本
这个方法会抛出一个异常,throws:表示的是可能出现异常,针对调用者必须进行处理
要使用clone方法,当前某个对象所在的类必须实现"标记接口"Cloneable(没有字段(成员变量),也没有成员方法)
实现这个接口,那么就可以使用Object的clone()方法
9. Scanner
Scanner类:文本扫描器 java.util.Scaner ;
构造方法:
public Scanner(InputStream source) :创建一个文本扫描器
形式参数是一个抽象类--->
它通过System类里面的public static final InputStream in
System类中
public final static InputStream in = null;
本地方法(非Java语言实现)---> private static native void setIn0(InputStream in);
底层方法一定会创建系统资源---->读取用户输入的 字符(整数,字符串...)
Scanner类提供判断功能: 防止出现输入的类型和结果类型不匹配!
public boolean hasNextXXX():判断下一个录入的是否为指定的XXX类型
XXX nextXXX() 获取功能
举例:
public boolean hasNextInt()
int nextInt()
如果先录入int,在录入String---->nextLine()---- 录入的字符串数据被漏掉
解决方案;
1)直接使用next()---->String
2)在使用nextLine()之前,在创建Scanner对象即可
统一先用String----->全部接收 ----->后期可以通过Integer的特有功能将整数---->String
前提条件:String---->数字字符串 "1","2","3"
举例:
本身:int
录入5个学生的语文,数学,英语成绩,按照总分从高到底排序(可以TreeSet集合进行排序)
语文成绩,数学成绩,英语成绩---->nextLine()---->String
"98" "78" "60"
String--- 基本类型的包装类类型Integer--->int
八. String大家族
1. String构造方法
java.lang.String:代表的字符串:
字符串是一个常量,一旦被赋值了,其值(地址值)不能被更改
推荐的使用方式:
String 变量名 = "xxxx" ;//xxxx代表 的当前String的实例
String类常用的功能:
获取功能:
int length():获取字符串长
面试题:
在数组中有没有length方法,在String类中有没有length方法,在集合中有没有length方法
数组中没有length方法,length属性
int[] arr = new int[3] ;
arr.length;
String类中有length()
集合中没有length(),----->size()获取元素数
构造方法:
(1). public String(): //空参构造:空字符序列
例: String s = new String() ;
System.out.println("s:"+s); //String类重写了Object的toString(),
System.out.println(s.length());
(2). public String(byte[] bytes)://将一个字节数组构造成一个字符串,使用平台默认的字符集(utf-8:一个中文对应三个字节) 解码
例: byte[] bytes = {97,98,99,100,101} ;
String s2 = new String(bytes) ;
System.out.println(s2);
编码和解码---保证字符集统一
编码:将一个能看懂的字符串---->字节 "今天老地方见" utf-8
解码:将看不懂的字节---->字符串 "今天老地方见" gbk
(3). public String(byte[] bytes,字符集):使用指定的字符集,将字节数组构造成一个字符串
(4). public String(byte[] bytes,int offset,int length):将指定的部分字节数组转换成字符串
参数1:字节数组对象,参数2:指定的角标值 参数3:指定长度
例: String s3 = new String(bytes,2,2) ;
System.out.println(s3);
System.out.println(s3.length());
(5). public String(char[] value):将字符数组构造成一字符串
例: char[] chs = {'我','爱','高','圆','圆'} ;
String s4 = new String(chs) ;
System.out.println(s4);
System.out.println(s4.length());
(6). public String(char[] value,int offset,int count):将部分字符数组转换成字符串
例: String s5 = new String(chs,1,4) ;
System.out.println(s5);
System.out.println(s5.length());
(7). public String(String original):构造一个字符串,参数为字符串常量
例: String s6 = new String("hello") ; //创建字符串对象,常量值:hello
System.out.println(s6);
String s7 = "hello" ; //推荐的方式
System.out.println(s7)
//面试题:
String s1 = "hello" ;
String s2 = new String("hello") ;
在内存中分别创建了几个对象?
第一个创建了一个对象,直接在常量池创建,开辟常量池空间
第二个:创建了两个对象,一个堆内存中开辟空间,一个指向常量池(不推荐)
/**
* String类型重写了Object的equals方法
* Object 的equals
*
* public boolean equals(Object obj) {
* return (this == obj); //默认比较的地址值
* }
* class String{
* private final char value[]; 属性 value 字符数组
* public boolean equals(Object anObject) { Object anObject = new String() ;
* if (this == anObject) { //判断当前字符串对象和传递进来S2对比
* return true; //判断地址值相同
* }
* if (anObject instanceof String) { //判断传进来的s2是否为String类型的实例
* String anotherString = (String)anObject; // 向下转型 String类型
* int n = value.length; //获取了字符数组长度 this.value.length----> int n = 5
* if (n == anotherString.value.length) { // if(s1的长度 5 == s2.value.length 5)
* char v1[] = value; //char v1[] = this.value; 将s1---->v1字符数组
* char v1[] = {'h','e','l','l','o'}
* char v2[] = anotherString.value; //char v2[] =s2.value; 将s2----->v2字符数组
* char v2[] = {'h','e','l','l','o'}
* int i = 0; //统计变量
* while (n-- != 0) { // i=0
* if (v1[i] != v2[i]) // v1[0] != v2[0] ---->'h' v1[1] != v2[1]
* return false;
* i++; /i=1
* }
* return true; //true
* }
* }
* return false;
* }
*
* }
*/
2. String类的常用的转换功能: (重点)
(1). byte[] getBytes() : 将字符串转换成字节数组 (编码)
如果方法为空参,使用平台默认的编码集进行编码(utf-8:一个中文对应三个字节)
例: String str = "中国" ;
byte[] bytes = str.getBytes();//默认utf-8
System.out.println(Arrays.toString(bytes));//[-28, -72, -83, -27, -101, -67]
(2). byte[] getBytes(String charset): 使用指定的字符集进行编码
解码的过程:将看不懂的字节数----->String
(3). String(byte[] bytes):使用默认字符集进行解码
例: String strResult = new String(bytes) ;// //使用平台默认解码集进行解码: utf-8
System.out.println(strResult);
(4). String(byte[] bytes,指定字符集)编码和解码必须要保证字符集统一
字符集:
gbk :一个中文两个字节(中国中文编码表)
gb2312:gbk升级版(含义有一个中文字符:中国的中文编码表)
iso-8859-1:拉丁文码表
utf-8:任何的浏览器--->都支持 utf-8格式 (后期统一个)
unicode:国际编码表
JS:日本国际 电脑系统 一个字符集
Arrays
静态功能:
(5). public static String toString(int/byte/float/double...[] a):将任意类型的数组---->String
(6). public char[] toCharArray(): 将字符串转换成字符数组
例: //定义一个字符串
String s2 = "helloworldJavaEE" ;
// public char[] toCharArray()
char[] chs = s2.toCharArray();
//遍历字符数组
for(int x = 0 ; x < chs.length; x ++){
System.out.println(chs[x]);
}
(7). public String toString(): 返回自己本身---"当前字符串的内容"
例: //System.out.println(s2.toString());
(8). public String toUpperCase(): 将字符串转换成大写
(9). public String toLowerCase(): 将字符串转换成小写java
例: System.out.println(s2.toUpperCase());
System.out.println(s2.toLowerCase());
3. String类型的判断功能
public boolean equals(Object anObject)://比较两个字符的内容是否相同 (区分大小写)
public boolean equalsIgnoreCase(String anotherString)://比较两个字符串是否相同(不区分大小写)
public boolean startsWith(String prefix)://判断字符串是否以指定的内容开头
public boolean endsWith(String suffix)://判断字符串是否以指定的内容结尾
需求:在某个时间点(今天下午18:00 将某个目录下的所有的以.java文件结尾删除)
Java中定时器类:Timer---->定时任务TimerTask(抽象类)
表示文件或者文件夹的抽象路径形式:File类
递归删除 (定义方法删除)
boolean isEmpty() 判断字符串是否为空 ://若为空,则返回true;否则返回false
String s = "" ;// 空字符串 ,存在String对象 ""
String s = null ; 空值 (空对象) null:引用类型的默认值
例:
String s1 = "helloJavaEE" ;
String s2 = "hellojavaee" ;
//比较两个字符的内容是否相同 (区分大小写)
System.out.println("equals:"+s1.equals(s2));
//比较两个字符的内容是否相同 (不区分大小写)
System.out.println("equalsIgnoreCase():"+s1.equalsIgnoreCase(s2));
/*
* public boolean startsWith(String prefix):判断字符串是否以指定的内容开头
* public boolean endsWith(String suffix):判断字符串是否以指定的内容结尾
* boolean isEmpty() 判断字符串是否为空 :若为空,则返回true;否则返回false
*/
System.out.println("startsWith():"+s1.startsWith("hel"));
System.out.println("startsWith():"+s1.startsWith("ak47"));
System.out.println("endsWith():"+s1.endsWith("EE"));
s1 = "" ; //length()---->长度0 (空字符序列)
System.out.println(s1.isEmpty());
4. String类的获取功能:(重点)
(1). int length(): //获取字符串长度
(2). public char charAt(int index); //获取指定索引处的字符
例: String str = "helloworldJavaEE" ;
System.out.println("charAt():"+str.charAt(4));
(3). public String concat(String str): //将指定的字符串和当前字符串进行拼接,获取一个新的字符串
例: System.out.println("concat:"+str.concat("R").concat("Go"));
(4). public int indexOf(int ch): //返回指定字符第一次出现的索引值
(5). public int lastIndexOf(int ch): //返回值指定字符最后一次出现的索引值
例: System.out.println("indexOf():"+str.indexOf("o"));
System.out.println("lastIndexOf():"+str.lastIndexOf("o"));
(6). public String[] split(String regex): //拆分功能:通过指定的格式将字符串---拆分字符串数组
例: String str2 = "JavaEE-Python-Go-R-C-C#-PHP" ;
String[] strArray = str2.split("-");
for(int x = 0 ; x < strArray.length ; x ++){
System.out.print(strArray[x]+"\t");
}
(7). public String substring(int beginIndex) ://从指定位置开始默认截取到末尾角标从0开始
(8). public String substring(int beginIndex,int endIndex)://从指定位置开始,截取到位置结束(包前不包右)
//只能取到endIndex-1处
例: String str = "helloworldJavaEE" ;
System.out.println("subString():"+str.substring(5));
System.out.println("subString():"+str.substring(5,9))
(9). public static String valueOf(boolean/int/long/float/double/char...Object b)//万能方法,将任意类型转换String //类型
5. 字符串其他功能:
(1). public String replace(char target,char replacement)://替换功将指定的内容使用target字符进行替换
例: String s = "helloworld" ;
System.out.println("replace():"+s.replace('l','k'));
(2). public String replaceAll(String regex, String replacement) ://将指定的和参数1正则表达式匹配的字符串 使用 //replacement进行替换
参数1:
[0-9] --->如果字符是数字字符
参数2: "*"替换掉
(3). public String trim()://去除字符串两端的空格
例: String s3 = " hello " ;
System.out.println("s3:"+s3.trim()+"----");
重点:
(4). public int compareTo(String anotherString):按照字典顺序比较,返回值是int.
String s1 = "hello" ;
String s2 = "hel" ;
String s3 = "abc" ;
s1.compareTo(s2); //2
s1.compareTo(s3) ;//7
/*
String类型---内置一个属性: char[] value
//1)字符串底层---->字符数组 s1和s2--->转换字符串数组 获取长度 5 和 3
2)通过Math的min方法(5,3) --->获取最小值 int lim = 3 ;
3) 创建两个数组对象 char[] c1 = {'h','e','l','l','o'}
char[] c2 = {'h','e','l'} ;
4)判断 定义统计变量 k = 0
while(k < lim){
if(c1[k] != c2[k]){
return 对应的字符值进行相减
return 'h' - 'a' = 104 - 97 = 7
}
k ++ ; //统计变量++
}
return 字符串的长度相减(字符数组长度相减)
*/
6. int 和 String 类型之间如何转换
//int---->String
//integer类型的静态功能toString
public static String toString(int i)
//String--->int
//Integer的静态功能
public static int parseInt(String s)
//String ---->Integer ---->int
String s = "100" ;
Integer i = new Integer(s) ;
int num = i.intValue() ;
7. StringBuffer 的构造方法以及功能
StringBuffer :字符串缓冲区 ---->类似于String,但是不一样 (可变的字符序列)
线程安全------>线程----(多线程中说)
线程依赖于进程存在!进程,能够被系统资源调用的独立单位
一个进程可以有多个线程,每一个线程----->"执行单元"(任务)
线程安全---->同步的----->执行效率低
举例:
银行类的网站/医疗网站
ATM机取钱---->插卡--->输入密码---->查询余额---->取钱
StringBuilder:和StringBuffer具有相互兼容的API,它是线程不安全的类---->不同步----->执行效率高
举例:
论坛网站
博客...
单线程程序中:jvm在进行编译的时候 使用StringBuilder去替换StringBuffer
//StringBuffer的构造方法:
public StringBuffer() : 空参构造,创建一个空字符序列的字符串缓冲去 (推荐)
public StringBuffer(int capacity): 构造一个字符串缓冲区对象,指定容量大小
public StringBuffer(String str): 指定字符序列,长度加上初始容量16(总容量)
//获取功能:
public int length():获取字符数(长度)
public int capacity():获取字符串缓冲区容量
//StringBuffer常用功能
StringBuffer的反转功能:reverse()
StringBuffer的追加功能: append(xxx)
StringBuffer的删除工能:deleteCharAt(int index)、delete(int start,int end)
StringBuffer的截取功能: subString(int bengin,int end)
StringBuffer的截取功能: subString(int bengin)
StringBuffer的插入功能: insert(int offset,String str)
8. StringBuffer,StringBuilder的区别
共同点:
两个都都是字符串缓冲区,支持可变的字符序列!
不同点:
StringBuffer:线程安全的类---->同步的(多线程:同步锁:源码几乎所有的方法都是同步方法 synchronized)
执行效率低
StringBuilder:线程不安全的类---->不同步----->执行效率高
单线程程序中,只考虑执行效率不考虑安全,所以StringBuilder类用作StringBuffer的简易替换
多线程环境中,要考虑安全问题只能使用StringBuffer,
线程安全的类:StringBuffer,Vector(List接口的子类)
9. StringBuffer和数组的区别
共同点:都是容器,都可以存储任意类型的元素 , 可以存储基本类型,也可以存储引用类型
数组---->同一种类型的元素 长度是固定的
如果需求中长度是不断变化的,那么数组用不了,考虑:StringBuffer/集合
StringBuffer---->存储不同类型的元素 append(int/char/double/Object/foat...) 长度是可变的
借助StringBuffer的功能:reverse()/append()追加----->转换成String形式体现
10. StringBuffer,StringBuilder和String的区别
String:字符串是一个常量,一旦被赋值,其值不能更改/作为形式参数属于特殊的引用类型,形式参数的改变不会实际参数
StringBuffer:可变的字符序列,线程安全的类----同步的----->执行效率低(线程角度)
StringBuilder:可变的字符序列.和StringBuffer具有相互兼容的api,单线程程序中(只考虑执行效率,不考虑安全问题)会使用StringBuilder替代StringBuffer
作为方法的形式参数,形参的改变会直接影响实际参数
11. String类的遍历
//将字符串的每一个字符分别输出! charAt(int index)
String str = "helloJavaEE" ;
//循环改进: 利用String类的length():获取字符串长度 + charAt(int index)
for(int x = 0 ;x < str.length() ; x ++){
System.out.println(str.charAt(x));//charAt(0)
}
//使用String类的转换功能
//String---->字符数组toCharArray()--->char[]
char[] chs = str.toCharArray();
for(int x = 0 ; x < chs.length ; x ++){
char ch = chs[x] ;
System.out.println(ch);
}
13. String类的字符串反转,判断字符串是否为对称字符串(reverse)
public class StringTest4 {
public static void main(String[] args) {
//创建键盘录入对象
Scanner sc = new Scanner(System.in) ;
//提示并录入数据
System.out.println("请您输入一个字符串:");
String line = sc.nextLine() ;
//方式2:使用StringBuffer的功能改进
boolean flag2 = compare2(line) ;
System.out.println(flag2);
private static boolean compare2(String line) {
/*
StringBuffer sb = new StringBuffer(line) ;
String str = sb.reverse().toString();
return str.equals(line) ;
*/
return new StringBuffer(line).reverse().toString().equals(line) ;
}
14. String类的equals方法表示什么意思
String类底层已经针对Object的equals和hashCode方法进行了重写
hashCode():String对象的哈希码值是否相同,哈希码值相同的不一定内容就相同,所以它需要覆盖equals方法
比较的字符串内容是否相同.
String s1 = "hello" ;
String s2 = new String("hello") ;
s1 ==s2---> false
s1.equals(s2) ---->true
15. StringBuffer和String如何转换
//String--->StringBuffer
String s = "hello" ;
//使用StringBuffer的有参构造方法
StringBuffer sb = new StringBuffer(s)
//或者是StringBuffer的追加功能
StringBuffer sb = new StringBuffer() ;
sb.append(s) ;
//StringBuffer--->String
//String类的构造方法 String(StringBuffer)
StringBuffer buffe = new StringBuffer("world") ;
String str = new String(buffer) ;
//第二种方式:StringBuffer的toString方法
九. Integer
1. 基本类型对应的包装类类型
整数类型 引用类型(默认值都是null)
byte Byte
short Short
int Integer
long Long
*
浮点类型
float Float
double Double
字符类型
char Character
布尔类型
boolean Boolean
2. 通过Integer得到int类型的取值范围
public static String toBinaryString(int i)://将整数---->二进制 的字符串
public static String toOctalString(int i)://将整数---->八进制的字符串
public static String toHexString(int i)://将整数---->十六进制数据
public static final int MAX_VALUE:int的最大值
public static final int MIN_VALUE:int的最小值
System.out.println(Integer.toBinaryString(100)); // 1100100
System.out.println(Integer.toOctalString(100)); // 144
System.out.println(Integer.toHexString(100)); //64
System.out.println(Integer.MIN_VALUE);//-2的31次方
System.out.println(Integer.MAX_VALUE);//2的31次方-1
3. Integer的构造方法
Integer(int value):可以将int类型保证为Integer类型
Integer(String s) throws NumberForamtException: 抛出一个数字格式化异常
注:当前字符串如果不是能够解析的整数的,就会出现数字格式化异常,s必须为 数字字符串
String s = "50" ;
Integer integer2 = new Integer(s) ;
System.out.println(integer2);
4.自动拆装箱
基本类型---> 对应的包装类类型 (装箱)
对应的包装类型---->基本类型 (拆箱)
方式:int---->Integer---->String //Integer作为桥梁
int i = 50 ;
Integer ii = new Integer(i) ;
String str2 = ii.toString();
System.out.println(str2);//50
方式:String ---->Integer---->int
String s = "100" ;
Integer integer = new Integer(s) ;
int result2 = integer.intValue();
System.out.println(result2);//100
> Integer的内部缓存区:IntegerCache
> low =-128 high=127
直接赋值的形式----》执行的底层Integer.valueOf(int i){}
> Integer i = 128 ; //new Integer(128)
> Integer i2 =128 ; //new Integer(128)
> System.out.println(i == i2) ;false
十. Charcater : char类型的包装类类型
1. 构造方法
public Character(char value)
//创建字符类对象
//Character character = new Character('a') ;
Character character = new Character((char)(97)) ;
System.out.println(character); ----------a
2.主要功能
public static boolean isUpperCase(char ch)://判断当前字符是否大写字母字符
public static boolean isLowerCAse(char ch)://是否为小写字母字符
public static boolean isDigit(char ch)://是否为数字字符
3.例题
//定义三个统计变量
int bigCount = 0 ;
int smallCount = 0 ;
int numberCount = 0;
//创建键盘录入对象
Scanner sc = new Scanner(System.in) ;
//提示并录入数据
System.out.println("请您输入一个数据:");
String line = sc.nextLine() ;
//转换成字符数组
char[] chs = line.toCharArray();
for (int i = 0; i <chs.length ; i++) {
char ch = chs[i] ;
//直接判断
if(Character.isDigit(ch)){
numberCount ++ ;
}else if(Character.isUpperCase(ch)){
bigCount ++ ;
}else if(Character.isLowerCase(ch)){
smallCount ++;
}
}
十一. 日历类
1. Data
public Date()://当前系统时间格式
public Date(long date):参数为 时间毫秒值---->Date对象 (1970年1月1日...)
//创建日期类对象
Date date = new Date() ;
System.out.println(date);
long time = 60*60 ;
Date date2 = new Date(time) ;
System.out.println(date2);
2. Date和String类型如何转换
//java.util.Date---->String: 格式化操作
//1)创建Date对象
Date date = new Date() ;
//2)创建SimpleDateFormat对象
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd") ;
//3)格式化的操作
String textDate = sdf.foramt(date) ; //使用textDate:日期文本字符串
//String:日期文本字符串----->java.util.Date :解析操作
//1)日期文本字符串
String source = "2021-7-29" ; //格式
//2)创建SimpleDateFormat对象
SimplDateFormat sdf2 = new SimpleDateFormat("yyyy-MM-dd") ; //模式必须和String的格式一致,否则解析出错
//3)解析操作
Date date2 = sdf2.parse(source) ; //使用Date
3. 静态功能,返回值是它自己本身 public static Calendar getInstance()
public int get(int field)://根据给定日历字段----获取日历字段的值(系统的日历)
Calendar calendar = Calendar.getInstance();
int year = calendar.get(Calendar.YEAR) ;
int month = calendar.get(Calendar.MONTH) ;
int date = calendar.get(Calendar.DATE) ;
public abstract void add(int field,int amount)://给指定的日历字段,添加或者减去时间偏移量
参数1:日历字段
参数2:偏移量
int year = calendar.add(Calendar.YEAR,-3);
十二. Random(伪随机数生成器)
1.构造方法
public Random(): 产生一个随机生成器对象,通过成员方法随机数每次没不一样的(推荐)
public Random(long seed) :参数为long类型的值(随机数流:种子),每次通过成员方法获取随机数产生的随机数相同的
2. 获取随机数的成员方法
public int nextInt():获取的值的范围是int类型的取值范围(-2的31次方到2的31次方-1)
public int nextInt(int n):获取的0-n之间的数据 (不包含n)
产生随机数:
Math类的random方法
public static double random();
Random类:也能够去使用
无参构造方法 + 成员方法
public Random():+ public int nextInt(int n)
3. java.lang.Math :针对数学运算的工具类,提供了很多方法
public static int abs(int a)://绝对值方法
public static double ceil(double a)://向上取整
public static double floor(double a)://向下取整
public static int max(int a,int b)://获取最大值
public static int min(int a,int b)://获取最小值
public static double pow(double a,double b)://a的b次幂
public static double random():[0.0,1.0)://随机数
public static long round(double a)://四舍五入
public static double sqrt(double a)://开平方根
Math类中的功能都是静态的,里面构造方法私有了!
一般情况:工具类中构造方法都是会私有化(自定义的工具类),提供对外静态的公共访问方法
(Java设计模式:单例模式)
JDK5的静态导入特性,必须方法静态的(导入到方法的级别)
Math类的功能都是静态的,就可以使用静态导入
import static 包名.类名.方法名;
前提不能和其他方法名重名;
4. BigDecimal
小数要进行精确计算-还可以计算的同时保留小数点后的有效位数
Java提供的类: BigDecimal
构造方法:
public BigDecimal(String value):数字字符串
成员方法:
public BigDecimal add(BigDecimal augend)//加
public BigDecimal subtract(BigDecimal subtrahend)//减
public BigDecimal multiply(BigDecimal multiplicand)//乘
public BigDecimal divide(BigDecimal divisor)//除
public BigDecimal divide(BigDecimal divisor,int scale,int roundingMode)
参数1:商
参数2:小数点后保留的有效位数
参数3:舍入模式 :四舍五入
5. ObjectArrayDemo 对象数组:能够存储对象的数组.
十三. Collection
Collection:集合层次的根接口
一些集合允许元素重复(List),一些集合不允许元素重复(Set)
一些集合有序(存储和取出一致)(List),一些集合无序(存储和取出不一致)(Set),
JDK不提供此接口的任何直接实现:它提供了更具体的子接口的实现,如Set和List
Collection
List:
最具体的子实现类ArrayList,LinkedList,Vector
基本功能:
添加
boolean add(Object e)://添加元素 E(Element)
删除:
void clear() // 暴力删除(将集合的素有元素全部干掉)
boolean remove(Object o)://从集合中删除指定的元素
获取集合的元素数 :int size()
判断功能:boolean isEmpty()://判断集合是否为空,为空元素,则返回true
boolean contains(Object o)://判断集合中是否包含指定元素,包含则返回true
1. Collection的高级功能
boolean addAll(Collection c)://添加一个集合中的所有元素
boolean containsAll(Collection c)://包含一个集合中的所有元素
boolean removeAll(Collection c)://删除集合中的所有元素, (删除一个算删除,还是删除所有)
boolean retainAll(Collection c)://A集合对B集合求交集, boolean的返回值是什么意思,交集的元素是保存在A中还是B中
//Collection最基本的遍历功能,不属于集合的专有遍历
Object[] toArray():将集合转换成了对象数组
2. Collection的迭代器:集合的专有遍历方式
Iterator iterator():返回值类型接口类型,需要返回的子实现类对象
Iterator接口:
boolean hasNext():判断迭代器中是否存在下一个元素
Object next(): 获取下一个可以遍历的元素
给Collection中存储String类型,遍历出来
public class CollectionTest {
public static void main(String[] args) {
//创建集合对象
Collection c = new ArrayList() ; //List接口的子实现类 (重复元素)
//添加元素
c.add("hello") ;
c.add("world") ;
c.add("javaee") ;
// System.out.println(c);
//获取Collection的迭代器Iterator iterator()
Iterator it = c.iterator();
//如果现在明确存储了3个元素,以后这些数据可能数据库获取的一个列表集合数据,一般while循环
while(it.hasNext()){//判断迭代器中有下一个元素
//才获取
Object obj = it.next();// Object obj = new String("hello") ...
// System.out.println(obj+"----"+obj.length());
//获取的元素同时,还要获取当前存储元素的长度 ---->String类型 length()
String str = (String) obj;//向下转型
System.out.println(str+"----"+str.length());
}
}
}
3.泛型<E/T>
集合类型<引用数据类型> 集合对象名 = new 子实现类<引用数据类型>() ;
泛型的好处:
1)将运行时期异常提前了编译时期
2)避免了强制类型转换
3)提高了程序安全性
public class GenericDemo {
public static void main(String[] args) {
//创建Collection集合对象
Collection<String> c = new ArrayList<String>() ; //new XXX<数据类型>: jdk7以后泛型推断
c.add("hello") ;
c.add("高圆圆") ;
c.add("你好吗") ;
// c.add(100) ;
//获取迭代器Iteratr<E>是集合中存储的泛型是一致的
Iterator<String> it = c.iterator();
while(it.hasNext()){
//获取String字符串的同时,还要获取长度
String str = it.next();
System.out.println(str+"---"+str.length());
}
}
}
4. Collection的面试题
集合和数组的区别
1)长度区别
数组:长度固定
集合:长度可变
2)存储数据类型的区别
数组:
可以存储基本数据类型,也可以存储引用数据类型
int[] arr = {100,200,50,"hello"} ;不行的
集合:前提条件:集合中加入泛型<> 也是在模拟数组的特点:
只能存储引用类型 Collection<E> :泛型<引用类型>
3)存储元素的区别:
数组:
存储的元素必须为同一种数据类型
举例:
水杯中加入水
集合:如果没有加入泛型 :就出任意类型的元素(必须引用类型)
举例:
水杯加入水,可乐,加入威士忌
十四. List
1. List 集合的特点
1.有序(存储元素和取出元素一致)
2.允许元素重复
具备Collection相关的功能
Object [] toArray()
Iterator iterator()
2.特有功能
void add(int index,Object element):在指定的索引处插 入元素
Object get(int index):获取指定位置处的元素 + int size():一种新的集合遍历方式
Object remove(int index):删除指定位置处的元素
Object set(int index,E element):修改指定位置处的元素(替换)
ListIterator<E> listIterator():列表迭代器
ListIterator接口:
void add(E e)有添加
remove():有删除
3. List集合的遍历方式
Object[] toArray()
Iterator iterator()
Object get(int index):获取指定位置处的元素 + int size():一种新的集合遍历方式
ListIterator<E> listIterator():列表迭代器 :List集合专有遍历方式
public class ListTest {
public static void main(String[] args) {
//创建List集合对象
List<String> list = new ArrayList<>() ;
//添加元素
list.add("hello");
list.add("world");
list.add("java");
list.add("android");
//size()+get(int index)集合
for(int x = 0 ; x < list.size() ; x ++){
String s = list.get(x);
System.out.println(s+"---"+s.length());
}
System.out.println("-----------------------------------------------");
//List集合存储Student对象并进行遍历(学生:姓名,年龄)
List<Student> stuList = new ArrayList<>() ;//JDK7以后 泛型推断:自动的和前面的泛型类型一致!
//创建3个学生
Student s1 = new Student("张佳宁",31) ;
Student s2 = new Student("迪丽热巴",29) ;
Student s3 = new Student("张俊杰",20) ;
//添加到列表中
stuList.add(s1) ;
stuList.add(s2) ;
stuList.add(s3) ;
//遍历
//方式1:Object[] toArray()
Object[] objs = stuList.toArray();
for(int x = 0 ; x < objs.length ; x ++){
Student s = (Student) objs[x];
System.out.println(s.getName()+"----"+s.getAge());
}
System.out.println("--------------------------------------");
//Collection的迭代器
Iterator<Student> it = stuList.iterator();
while(it.hasNext()){
Student s = it.next() ;
System.out.println(s.getName()+"---"+s.getAge());
// System.out.println((it.next().getName()+"---"+(it.next().getAge())));
// next()只能使用一次,不能多次使用 //错误的用法
}
System.out.println("-------------------------------------");
//方式3:size()+get(int index)
for(int x = 0 ; x < stuList.size() ; x ++){
Student s = stuList.get(x);
System.out.println(s.getName()+"----"+s.getAge());
}
System.out.println("-----------------------------------------");
//正向遍历:ListIterator<E> listIterator():列表迭代器 :List集合专有遍历方式
ListIterator<Student> lit = stuList.listIterator();
/**
* ListIterator extends Iterator{}
*
* class ArrayList{
* List具体ArrayList子实现类重写了Iterator listiterator(){
*
* return new ListItr(0) ;
* }
*
* private class ListItr extends Itr implements Iterator{
*
* //具备hasNext()
* //next()
* }
*
* }
*/
while(lit.hasNext()){
Student student = lit.next();
System.out.println(student.getName()+"---"+student.getAge());
}
System.out.println("-----------------------------------------");
//逆向遍历:前提:必须有正向遍历
//ListIterator<E> listIterator()
//ListIterator:特有功能:
//boolean hasPrevious():是否有上一个元素可以迭代
//Object previous():获取上一个元素
while(lit.hasPrevious()){
Student student = lit.previous();
System.out.println(student.getName()+"---"+student.getAge());
}
}
}
4. LIst如何去重
(1).存储字符串类型
方式一:新建空集合思想
//新建一个空的集合List
List<String> newList = new ArrayList<>() ;
//遍历以前的集合
for(String s :list){
//使用新集合判断,不包含这个元素,说明该元素没有重复,就可以添加
if(!newList.contains(s)){
newList.add(s) ;
}
}
//遍历新的集合
for(String s:newList){
System.out.println(s);
}
方式二:利用选择排序的思想去完成
//利用选择排序的思想完成
for(int x = 0 ; x < list.size()-1 ; x ++){
for(int y = x +1 ; y < list.size() ; y++){
//如果后面的元素和前面的元素相同
if(list.get(y).equals(list.get(x))){
//通过集合remove掉
list.remove(y) ; // public Object remove(int index)
//角标--
y -- ;
}
}
}
for(String s:list){
System.out.println(s);
}
(2). 存储自定义对象
方式1:新建集合思想
contains(Object)方法依赖于Object的equals方法,所以集合存储的类型所在的类必须重写equals方法,否则默认使用
方式2:使用选择排序思想 将List存储的重复的学生对象进行重写!
//方式1:创建新的一个新集合
List<Student> newList = new ArrayList<>() ;
//遍历以前的集合获取每一个学生对象
for(Student s:list){
//如果当前newList不包含这个学生添加到新集合中
if(!newList.contains(s)){
newList.add(s) ;
}
}
//遍历新集合
for(Student student:newList){
System.out.println(student.getName()+"----"+student.getAge());
}
5. List的并发修改异常java.util.ConcurrentModificationException
集合在使用迭代器会经常出现的问题:并发修改异常,
当集合的元素正在被迭代器进行遍历,那么集合对象是不能够对元素进行增加或者删除 (一个线程正在遍历,一个线程在修改元素)
解决方案:
1)要么就是迭代器去遍历集合的元素,迭代器去添加元素 :列表迭代器才具备添加的动作
2)要么集合遍历,集合添加
public class ListTest2 {
public static void main(String[] args) {
//创建List集合对象
List<String> list = new ArrayList<>() ;
//给添加元素
list.add("hello") ;
list.add("world") ;
list.add("javaee") ;
//使用迭代器遍历
//Iterator iterator()
/* Iterator<String> it = list.iterator(); //"hello","world","javaee"
while(it.hasNext()){
String s = it.next() ;//"hello","world","javaee"
//判断
if("world".equals(s)){
list.add("javaEE") ;//集合对象添加的元素,迭代器不知道
}
}
System.out.println(list);*/
//解决方案1: 1)要么就是迭代器去遍历集合的元素,迭代器去添加元素 :列表迭代器才具备添加的动作
//ListIterator
//void add(E e)
/*ListIterator<String> lit = list.listIterator();
while(lit.hasNext()){
//获取
String s = lit.next();
//判断是否存在"world"元素
if("world".equals(s)){
//列表迭代器添加
lit.add("javaEE");
}
}*/
//方案2:要么集合遍历,集合添加
//size()+get(int index)
for(int x = 0 ; x < list.size(); x ++){
String s = list.get(x);
if("world".equals(s)){//将常量放前面,防止出现NullPointerException
list.add("javaEE");
}
}
System.out.println(list);
}
}
十五. Vector
1. Vector集合特有功能:
添加
public void addElement(Object obj):在vector对象的末尾添加元素 ------> 一直使用的add(Object e)
删除
public boolean removeElement(Object obj):删除元素
获取功能
public Object elementAt(int index):获取指定位置的元素---->类似于 public Object get(int index)
public Enumeration<E> elements() :Vector集合的专有遍历方式---->类似于 Iterator literator()
接口
boolean hasMoreElements():判断是否有更多的元素可以迭代
Object nextElement() 获取元素
2. Vector集合遍历方式
public Enumeration elements() Vector集合的专有遍历方式
public class VectorDemo {
public static void main(String[] args) {
//创建Vector集合对象
Vector<String> v = new Vector<>() ;
v.addElement("hello");
v.addElement("world");
v.addElement("SpringBoot");
v.addElement("SpringCloud") ;
//遍历:特有功能
Enumeration<String> en = v.elements(); //相当于Iterator
while(en.hasMoreElements()){
String s = en.nextElement();
System.out.println(s+"---"+s.length());
}
System.out.println("----------------------------------");
for(String s: v){
System.out.println(s+"----"+s.length());
}
}
}
十六. 增强for循环
1. 增强for循环
替代集合中迭代器去遍历集合使用的(优先在集合中使用)
格式:
for(存储的引用数据类型 变量名: 集合/数组对象){
//集合使用居多,数组一般都是使用普通for
使用变量名即可
}
注意事项:
当前集合对象不能为空 null :foreach语句:增强for它本身就是获取迭代器了,就会出现空指针异常
public class ForeachDemo {
public static void main(String[] args) {
//数组
int[] arr = {11,22,33,44,55} ;
for(int x = 0 ; x < arr.length ; x ++){
System.out.println(arr[x]);
}
System.out.println("--------------------------------");
/*
for(存储的引用数据类型 变量名: 集合/数组对象){
* 使用变量名即可
* }
*/
//对于数组来说:使用普通for
/* for(int a:arr){
System.out.println(a);
}*/
//创建List集合
List<String> list = new ArrayList<>() ;
list.add("hello") ;
list.add("world") ;
list.add("javaee") ;
/* for(String s:list){//替换迭代器使用
//如果存在world元素,添加一个android元素
//System.out.println(s);
if("world".equals(s)){
list.add("android") ;//出现并发修改异常
}
}
System.out.println(list);
*/
list = null ;
if(list!=null){
for(String s:list){//获取迭代器
System.out.println(s+"---"+s.length());
}
}else{
System.out.println("当前集合对象为null了");
}
}
}
2. 面试题
需求:
使用增强for遍历List,存储三个学生,遍历后获取学生信息(姓名和年龄)
public class ForeachTest {
public static void main(String[] args) {
//创建List
List<Student> list = new ArrayList<>() ;
//创建三个学生
Student s1 = new Student("张佳宁",29) ;
Student s2 = new Student("邓超",40) ;
Student s3 = new Student("黄海波",30) ;
list.add(s1) ;
list.add(s2) ;
list.add(s3) ;
//方式5:增强for循环
for (Student s: list) {
// System.out.println(s.getName()+"---"+s.getAge());
System.out.println(s); //对象名称:直接使用重写后的toString()
}
}
}
3. 插入排序
核心思想:使用1角标对应的元素进行和0角标比较
如果前面元素大,向右移动,确定角标1对应的元素的位置,再次使用2角标对应的元素依次和1和0都元素比较
依次这样比较
public class InsertSortTest {
public static void main(String[] args) {
//定义一个Integer数组: Integer实现的自然排序:元素能够按照升序默认排序
Integer[] arr = {34,8,64,51,32,21} ;
System.out.println("排序前:");
printArr(arr);
//定义一个功能
insertSort(arr) ;
System.out.println("排序后:");
printArr(arr);
}
//插入排序
private static void insertSort(Integer[] arr) {
//定义一个变量j
int j ; //j记录当前角标的变化
//定义变量 : p:表示一个比较次数 p=1,2,3,4,5 (每一移动的元素的位置)
for(int p = 1 ; p < arr.length ; p ++ ){ //比较次数 p=2
//定义临时变量temp
Integer temp = arr[p] ; //temp = 8; temp = 64
//开始比较
for(j = p ; j>0 && temp.compareTo(arr[j-1])<0; j-- ){ // j= 1 ; 1>0&& 8 < 34 j-- : j= 0
//j=2 ; 2>0 && 64 < 32
//数据移动
arr[j] = arr[j-1] ;
}
//确定temp的位置:8的位置 64的位置:p=2
arr[j] = temp ; // 没有移动
}
}
public static void printArr(Integer[] arr){
System.out.print("[");
for(int x = 0 ; x < arr.length ; x ++){
if(x == arr.length -1){
System.out.println(arr[x] +"]");
}else{
System.out.print(arr[x]+", ");
}
}
}
}