ArrayList
数组的长度不可以发生改变,但是ArrayList集合的长度是可以随意变化的。
对于ArrayList来说,有一个尖括号代表泛型
泛型:也就是装在集合当中的所有元素,全都是统一的某种类型。
注意:泛型只能是引用类型,不能是基本类型
ArrayList<String> list = new ArrayList<>();
备注:从JDK 1.7+ 开始,右侧的尖括号内容可以不写内容,但是<>本身还是要写的。
ArrayList当中的常用方法有:
public boolean add(E e) : 向集合当中添加元素,参数的类型和泛型一致。返回值代表添加是否成功。
备注:对于ArrayList集合来说,add添加动作一定是成功的,所以返回值可用可不用。但是对于其他集合来说,add添加动作不一定成功。
// 向集合中添加元素: add
boolean success = list.add("一辈子");
System.out.println("添加动作是否成功:" + success);
System.out.println(list);
public E get(int index): 从集合当中获取元素,参数是索引编号,返回值就是对应位置的元素。
// 从集合中获取元素
String s = list.get(0);
System.out.println(s);
public E remove(int index): 从集合当中删除元素,参数是索引编号,返回值就是被删除掉的元素。
// 从集合中删除元素
String removed = list.remove(2);
System.out.println(list);
public int size(): 获取集合的尺寸长度,返回值是集合中包含的元素个数。
// 获取集合的长度
int size = list.size();
System.out.println(size);
如果希望向集合ArrayList当中存储基本类型数据,必须使用基本类型对应的"包装类”
基本类型 包装类(引用类型 包装类都位于java.lang包下)
byte Byte
short Short
int Integer
long Long
float Float
double Double
char Character
boolean Boolean
自动装箱: 基本类型 -> 包装类型
自动拆箱: 引用类型 -> 基本类型
String类
java.lang.String类代表字符串
String
类代表字符串。Java 程序中的所有字符串字面值(如 "abc"
)都作为此类的实例实现。 也就是说,程序当中所有的双引号字符串都是String类
的对象,就算没有new,也照样是 。
字符串的特点
- 字符串的内容永不可变。
重点
- 正是因为字符串不可改变,所以字符串是可以共享使用的。
- 字符串效果上相当于是char[ ]字符数组,但是底层原理是byte[ ]字节数组
创建字符串的常见3+1中方式:
3种构造方法:
public String() : 创建一个空白字符串,不含有任何内容
//使用空参构造
String str1 = new String(); //小括号留空,说明字符串什么内容也没有
System.out.println("第一个字符串:" + str1);
public String(char[] array): 根据字符数组的内容,来创建对应的字符串
//根据字符数组创建字符串
char[] charArray = {'A', 'B', 'C'};
String str2 = new String(charArray);
System.out.println("第二个字符串:" + str2);
public String(byte[] array): 根据字节数组的内容,来创建对应的字符串
byte[] byteArray = {97, 98, 99};
String str3 = new String(byteArray);
System.out.println("第三个字符串:" + str3);
1种直接创建
String str4 = "hello";
字符串常量池:程序当中直接写上的双引号字符串,就在字符串常量池中。
对于基本类型来说,== 是进行数值的比较
对于引用类型来说,==是进行地址值的比较
== 是进行对象的地址值的比较,如果确实需要字符串的内容比较,可以使用两个方法:
字符串的内容比较:
public boolean equals(Object obj) : 参数可以是任何对象,只有参数是一个字符串并且内容相同的才会是true;否则返回false
注意事项:
1. 任何对象都能用Object进行接收
2. equals方法具有对称性,也就是a.equals(b)和b.equals(a)效果一样。
3. 如果比较双方一个常量一个变量,推荐把常量字符串写在前面
推荐:"abc".equals(str) 不推荐:str.equals("abc")
public boolean equalsIgnoreCase(Object obj) : 不区分大小写比较
String 当中与获取相关的常用方法有:
public int length(): 获取字符串当中含有的字符个数,拿到字符串长度。
public String concat(String str): 将当前字符串和参数字符串拼接成为返回值新的字符串
public char charAt(int index): 获取指定索引位置的单个字符
public int indexOf(String str): 查找参数字符串在本字符串当中首次出现的索引位置,如果没有返回-1
字符串的截取方法:
public String substring(int index): 截取从参数位置一直到字符串结尾,返回新字符串
public String substring(int begin, int end): 截取从begin开始,一直到end结束,中间的字符串
备注:[begin, end),包含左边,不包含右边。
注意:下面这种写法,字符串的内容仍然是没有改变的,下面的两个字符串:"Hello" , "Java". strA当中保存的是地址值。本来地址值是Hello的0X666,后来地址值变成了Java的0x999;
String strA = "Hello";
System.out.println(StrA); //Hello
strA = "Java";
system.out.println(strA); //Java
String当中与转换相关的常用方法:
public char[] toCharArray(): 将当前字符串拆分成为字符数组作为返回值
public byte[] getBytes(): 获得当前字符串底层的字节数组
public String replace(CharSequence oldString, CharSequence newString): 将所有出现的老字符串替换成为新的字符串,返回替换之后的结果新字符串。
分割字符串的方法:
public String[] split(String regex): 按照参数规则,将字符串切分成为若干部分
注意事项:如果按照英文句点"." 来切分的话,需要使用 "\\."来使用。因为英文句点在正则表达式中有特殊含义。
static关键字
- 如果一个成员变量使用了static关键字,那么这个变量不再属于对象自己,而是属于所在的类。多个对象共享同一份数据。
- 一旦使用static修饰成员方法 ,那么这就成为了静态方法。静态方法不属于对象单独所有,而属于类
- 如果没有static关键字,那么必须首先创建对象,然后再通过对象调用其方法。
- 对于静态方法来说,可以直接使用类名称来直接调用(推荐)。
- 总结:无论是成员变量还是成员方法,如果有了static,都推荐使用类名称来进行调用
- 静态变量: 类名称.静态变量
- 静态方法: 类名称.静态方法();
- 备注:对于自己类中的静态方法,调用时类名称可以省略。
- 注意:
- 静态不能直接访问非静态。原因是因为内存当中是先有静态内容,然后再有非静态内容 (古人不知道后人,后人知道古人)。
- 静态方法当中不能用this关键字。原因是因为this代表对象,通过谁调用的方法,谁就是对象。
- 静态static内存图
- 静态代码块
格式:
public class 类名称 {
static {
//静态代码块内容
}
}
特点:当第一次用到本类时,静态代码块执行唯一的一次
静态内容总是优先于非静态,所以静态代码块比构造方法先执行。
典型用途: 用来一次性地对静态成员变量进行赋值
数组工具类Arrays
java.util.Arrays是一个与数组相关的工具类,里面提供了大量的静态方法,用来实现数组的常见操作。
public static String toString(数组) : 将参数数组变成字符串(按照默认格式)
public static void sort(数组): 按照默认升序(从小到大)对数组元素进行排序
备注:
1.如果是数值,sort默认按照升序从小到大。
2.如果是字符串,sort默认按照字母升序
3.如果是自定义类型,那么这个自定义的类需要有Comparable或者Comparator接口支持。
常用Math类
java.util.Math类是数学相关的工具类,里面提供了大量的静态方法,完成与数学运算相关的操作
public static double abs(double num): 获取绝对值。
public static double ceil(double num): 向上取整
public static double floor(double num): 向下取整
public static long round(double num): 四舍五入
接口的使用:
定义: 接口就是多个类的公共规范,它属于一种引用类型,最重要的内容是其中的抽象方法 。
接口定义格式:
public interface 接口名称 {
// 接口内容
}
备注:换成了关键字interface之后,编译生成的字节码文件仍然是:.java -> .class
// 如果是java 7,那么接口可以包含的内容有:
1. 常量
2. 抽象方法
注:抽象方法定义格式:public abstract void methodAbs();
// 如果是Java 8, 还可以额外包含有:
3. 默认方法
4. 静态方法
// 如果是Java 9,还可以额外包含有:
5. 私有方法
在任何版本的Java中,接口都能定义抽象方法。
格式: public abstract 返回值类型 方法名称(参数列表);
注意事项:
- 接口当中的抽象方法,修饰符必须是两个关键字:public abstract。(也可以省略其一或全不写)
- 方法的3要素,可以随意定义。
接口使用步骤: 实现类 -> 创建实现类对象
- 接口不能直接使用,必须有一个实现类 来 实现 该接口。
格式:public class 实现类名称 implements 接口名称 {
// …
}
- 接口的实现类必须覆盖重写(即实现)接口中所有抽象方法。
实现:去掉abstract关键字,加上方法体大括号 - 创建实现类的对象,进行使用。
注意事项:如果实现类并没有覆盖重写接口中所有的抽象方法,那么这个实现类自己就必须是抽象类。
从Java 8开始,接口里允许定义默认方法。
格式:
public default 返回值类型 方法名称(参数列表) {
方法体
}
备注:接口当中的默认方法,可以解决接口的升级问题。
- 接口的默认方法,可以通过接口实现类对象,直接调用。
- 接口的默认方法,也可以被接口实现类进行覆盖重写。
备注:调用抽象类方法,实际上运行的是右侧实现类。
从Java 8开始,接口里允许定义静态方法。
格式:
public static 返回值类型 方法名称(参数列表){
// 方法体
}
注意事项:不能通过接口实现类的对象来调用接口当中的静态方法。
正确用法:通过接口名称,直接调用其中的静态方法
格式:接口名称.静态方法名(参数);
从Java 9开始,接口里允许定义私有方法。
1. 普通私有方法,解决多个默认方法之间代码重复问题。
格式 :
private 返回值类型 方法名称(参数列表) {
方法体
}
2. 静态私有方法,解决多个静态方法之间重复代码问题
格式:
private static 返回值类型 方法名称(参数列表){
方法体
}
接口常量:
接口当中也可以定义 “成员变量” ,但是必须使用public static final 三个关键字修饰。从效果看,这其实就是接口的常量
格式:
public static final 数据类型 常量名称 = 数据值;
备注: 一旦使用final关键字进行修饰,说明不可改变。
注意事项:
1. 接口当中的常量,可以省略public static final,注意:不写也照样是原本的样子
2. 接口当中的常量,必须进行赋值;不能不赋值
3. 接口中常量的名称,使用完全大写的字母,用下划线进行分隔(推荐命名规则)
使用接口时,需要注意的事项:
1. 接口是没有静态代码块或者构造方法的。
2. 一个类的直接父类是唯一的,但是一个类可以同时实现多个接口。
格式:public class MyInterfaceImpl implements MyInterfaceA, MyInterfaceB {
// 覆盖重写所有抽象方法
}
3. 如果实现类所实现的多个接口当中,存在重复的抽象方法 ,那么只需要覆盖重写一次即可。
4. 如果实现类没有覆盖重写所有接口当中的抽象方法,那么实现类就必须是一个抽象类。
5. 如果实现类所实现的多个接口当中,存在重复的默认方法,那么实现类一定要对冲突的默认方法进行覆盖重写。
6. 一个类如果直接父类当中的方法,和接口当中的默认方法产生了冲突,优先使用父类当中的方法。
接口的扩展:
- 类与类之间是单继承的。直接父类只有一个
- 类与接口之间是多实现的。一个类可以实现多个接口。
- 接口与接口之间是多继承的。
注意事项:
- 多个父接口当中的抽象方法如果重复,没关系。
- 多个父接口当中的默认方法如果重复,那么子接口必须进行默认方法的覆盖重写 。而且必须带着default关键字。
多态性
1.多态的概述
2. 多态的使用
代码当中体现多态性,其实就是一句话:父类引用指向子类对象。
格式:
父类名称 对象名 = new 子类名称();
Fu obj = new Zi();
或者
接口名称 对象名 = new 实现类名称();
3. 多态访问成员变量和成员方法
访问成员变量的两种方式: (口诀:编译看左边,运行还看左边)
- 直接通过对象名称访问成员变量:看等号左边是谁,优先用谁,没有则向上找
- 间接通过成员方法访问成员变量:看该方法属于谁,优先用谁,没有则向上找
访问成员方法的访问规则: (口诀:编译看左边,运行看右边)
- 看new的是谁,就优先用谁,没有则向上找
4. 使用多态好处
5. 对象的上下转型
final关键字
1. final关键字概念与四种状态
概念:final关键字代表最终,不可改变的
常见四种用法:
- 可以用来修饰一个类
当final关键字用来修饰一个类的时候。
格式:
public final class 类名称 {
// ...
}
含义:当前这个类不能有任何的子类 (太监类)
注意:一个类如果是final类,那么其中所有的成员方法都无法进行覆盖重写(因为没有儿子)
- 可以用来修饰一个方法
当final关键字用来修饰一个方法的时候,这个方法就是最终的方法,也就是不能被覆盖重写。
格式:
修饰符 final 返回值类型 方法名称(参数列表){
// 方法体
}
注意事项:对于类,方法来说,abstract和final关键字不能同时使用,因为相互矛盾
- 可以用来修饰一个局部变量
格式:final int num = 200;
一旦使用final用来修饰局部变量,那么这个变量就不能进行更改
“一次赋值,终身不可改变”
注意:
1. 对于基本类型来说,不可变说的是变量当中的数据不可改变
2. 对于引用类型来说,不可变说的是变量当中的地址值不可改变
- 可以用来修饰一个成员变量
对于成员变量来说,如果使用final关键字修饰,那么这个变量也照样是不可改变
注意事项:
1. 由于成员变量具有默认值,所以用来final之后必须手动赋值,不会再给默认值了(如果给了默认的`0/0.0/null`的话岂不是就无法改变了)
2. 对于final的成员变量,要么使用直接赋值,要么通过构造方法赋值。二 者选其一。
3. 必须保证类当中所有重载的构造方法,都最终会对final的成员变量进行赋值(但是setter方法要注释掉).
权限修饰符
java中有四种权限修饰符:
大小关系及访问权限如下
public > protected > (default) > private
同一个类(我自己) YES YES YES YES
同一个包(我邻居) YES YES YES NO
不同包子类(我儿子) YES YES NO NO
不同包非子类(陌生人) YES NO NO NO
注意事项:(default)并不是关键字“default”,而是根本不写 如: ()int num = 100;
内部类
1. 内部类的概念与分类
概念: 如果一个事物的内部包含另一个事物,那么这就是一个类内部包含另一个类
例如:身体与心脏的关系。又如:汽车与发动机的关系。
分类:
- 成员内部类
修饰类 class 外部类名称 {
修饰符 class 成员 内部类名称 {
// ....
}
// ......
}
注意事项:内部访问外部类,不管什么修饰符度可以随意访问;但是外部访问内部类,需要使用内部类对象
如何使用成员内部类? 有两种方式:
1. 间接方式:在外部类的方法当中,使用内部类(如:在外部类中创建内部类对象,再访问其中的成员);然后main只需要调用外部类的方法即可间接访问到内部的成员
2. 直接方式:
公式:外部类名称.内部类名称 对象名 = new 外部类名称().new 内部类名称();
内部类的同名变量访问:外部类名称.this.变量名
- 局部内部类(包含匿名内部类)
如果一个类是定义在一个方法内部的,那么这就是一个局部类。
“局部”:只有当前所属的方法才能使用它,出了这个方法外面就不能用了。
定义格式:
修饰符 class 外部类方法 {
修饰符 返回值类型 外部类方法名称(参数列表) {
class 局部内部类名称 {
// ...
}
}
}
小节一下类的权限修饰符:
public > protected > (default) > private
定义一个类的时候,可以使用的权限修饰符规则:
1.外部类: public / (default)
2.成员内部类: public/protected/(default)/private
3.局部内部类:什么都不能写
如果希望访问所在方法的局部变量,那么这个局部变量必须是有效final的
原因:跟两者的生命周期有关
- new出来的对象在堆内存中
- 局部变量是跟着方法走的,在栈内存当中
- 方法运行结束后,立刻出栈,局部变量就会立刻消失。
- 但是new出来的对象会在堆当中持续存在,直到垃圾回收消失。
匿名内部类:
如果接口的实现类(或者是父类的子类),只需要使用唯一的一次,那么这种情况就可以省略掉该类的定义,而改为使用匿名内部类
。
匿名内部类的定义格式:
接口名称 对象名 = new 接口名称() {
// 覆盖重写所有抽象方法
};
对格式“new 接口名称() {…}”进行解析:
- new代表创建对象的动作
- 接口名称就是匿名内部类需要实现哪个接口
- {…} 大括号内部的才是匿名内部类的内容
另外还要注意几点问题:
- 匿名内部类,在
创建对象
的时候,只能使用唯一的一次。如果希望多次创建对象,而且类的内容一样的话,那么就必须使用单独定义的实现类了。 - 匿名对象,在
调用方法
的时候只能调用唯一一次。如果希望同一个对象,调用多次方法,那么必须给对象起个名字。 - 匿名内部类是省略了
实现类 / 子类名称
,但是匿名对象是省略了对象名称
。
强调:匿名内部类和匿名对象不是一回事!!!