基础
运算符
编译器优化
-
byte、short、char的赋值优化
-
常量优化
-
位运算
流程控制语句
switch
- 多个case后面的数值不可以重复。
- 不能写else,只能写default。
- switch后面小括号当中只能是下列数据类型:
- 基本数据类型:
byte/short/char/int
- 引用数据类型:String字符串、
enum枚举
- 基本数据类型:
穿透switch语句
-
switch语句格式很灵活:前后顺序可以颠倒,而且break语句还可以省略。
-
匹配哪一个case就从哪一个位置向下执行,直到遇到了break或者整体结束为止。
强制类型转换
-
数据溢出
byte = 127+1
-
精度损失
-
byte/short/char
这三种类型在运算的时候,都会被首先提升成为int
类型 -
boolean
类型不能发生数据类型转换
ASCII码表
48:‘0’
65:‘A’
97:‘a’
方法的重载
即在同一个类中,相同的方法名称,参数列表当中的参数类型、个数、顺序不同;
跟参数名称、权限修饰符和返回值类无关
数组
特点
- 引用数据类型
- 多个数据类型一致
- 长度在运行期间不可改变
初始化
在内存当中创建一个数组,并且向其中赋予一些默认值
动态:指定长度
int[] arrayA = new int[300];
静态:指定内容
int[] arrayA = new int[] {5,15,25};
省略的静态
int[] arrayA = {5,15,25};
默认值
使用动态初始化数组的时候,其中的元素将会自动拥有一个默认值,规则如下:
数据类型 | 默认值 |
---|---|
整数 | 0 |
浮点 | 0.0 |
字符 | ‘\u0000’(unicode 十六进制) |
布尔 | false |
引用 | null |
静态初始化其实也有默认值的过程,只不过系统自动马上替换了大括号中的值。
访问
-
索引
arr[1]
-
长度
arr.length
异常
- 数组索引越界异常:
ArrayIndexOutOfBoundsException
【arry.length-1】 - 空指针异常
NullPointerException
【没new】
数组反转
- 借助第三个变量,注意停止循环语句
/*
初始化语句:int min = 0, max = array.length - 1;
条件判断:min < max
步进表达式:min++, max--
循环体:用第三个变量倒手
*/
for(int min = 0, max = array.length - 1; min < max; min++, max--) {
int temp = array[min];
array[min] = array[max];
array[max] = temp;
}
局部变量和全局变量
局部变量
位置:在方法的内部或者为方法的参数
作用范围:只有在方法当中才可以使用
默认值:无,使用前需手动赋值
-
方法中的未初始化变量不可以直接打印或使用。
-
方法参数中的变量可以打印或使用,因为当方法调用时一定会给参数赋值!
-
内存位置:位于栈内存(和方法一起)
-
生命周期:随着方法进栈而诞生,随着方法出栈而消失
全局变量
- 位置:在方法的外部,类中。
- 作用范围:整个类通用
- 默认值:若未赋值,则与数组默认值相同
- 内存位置:堆内存
- 生命周期:成员变量:随着对象创建而生,随着对象被垃圾回收而消失
封装
布尔值的get、set方法
public void setMale(boolean b) {
male = b;
}
public boolean isMale() { //注意是isXxx
return male;
}
this
- 修饰方法中的变量,解决成员变量被隐藏的问题
构造方法
-
当一个对象被创建时候,构造方法用来初始化该对象,给对象的成员变量赋初始值。
-
所有的类都有构造方法,因为Java自动提供了一个无参数构造方法
-
构造方法也是可以重载的
-
一旦编写了至少一个构造方法,那么编译器将不再赠送
static关键字
修饰类
-
用static修饰内部类,普通类是不允许声明为静态的,只有内部类才可以。
-
被static修饰的内部类可以直接作为一个普通类来使用,而不需实例一个外部类
类变量
-
该类的每个对象都共享同一个类变量的值。
-
任何对象都可以更改该类变量的值,
-
可以在不创建该类的对象的情况下对类变量进行操作。
静态方法
对于本类中的静态方法
-
可以通过对象名进行调用
-
也可以直接根据类名称来调用
-
或者省略类名称(编译器会自动添加)
注意
- 静态方法可以直接访问类变量和静态方法
- 静态方法不能直接访问普通成员变量或成员方法
- 静态方法中,不能使用this关键字
静态代码块
随着类的加载而执行且执行一次**,优先于main方法和构造方法的执行**
- 它优先于对象存在,可以被所有对象共享
作用:给静态变量进行初始化赋值
继承
- 子类继承父类的属性和行为,使得子类对象具有与父类相同的属性、相同的行为
- 子类可以直接访问父类中的非私有的属性和行为。
- 继承描述的是事物之间的所属关系,这种关系是:is-a的关系。
- 类与类之间产生了关系,是多态的前提
- 提高代码的复用性
访问父类成员变量
- 使用父类方法
- super.父类成员变量名
方法重写
- 解决父子类成员方法重名
- 扩展父类方法功能
要求
-
返回值类型、函数名和参数列表都要相同。
-
子类方法的权限修饰符要大于等于父类权限。
-
子类方法的返回值范围要小于等于父类方法的返回值范围。
继承中的构造方法
-
子类是无法继承父类构造方法
- 构造方法的名字是与类名一致的
- 构造方法的作用是初始化成员变量的。
-
子类必须先调用父类构造方法,再执行子类构造方法,
super()
必须是子类构造方法的第一个语句 -
一个子类构造不能多次调用super构造
-
子类构造方法可以通过super关键字来调用父类重载构造
继承的特点
- Java只支持单继承,不支持多继承。
- Java支持多层继承(继承体系)
抽象
-
抽象类不能创建对象,如果创建,编译无法通过而报错。只能创建其非抽象子类的对象。
理解:假设创建了抽象类的对象,调用抽象的方法,而抽象方法没有具体的方法体,没有意义。
-
抽象类中,可以有构造方法,是供子类创建对象时,初始化父类成员使用的。
理解:子类的构造方法中,有默认的super(),需要访问父类构造方法。
-
抽象类中,不一定包含抽象方法,但是有抽象方法的类必定是抽象类。
理解:未包含抽象方法的抽象类,目的就是不想让调用者创建该类对象,通常用于某些特殊的类结构设计。
-
抽象类的子类,必须重写抽象父类中所有的抽象方法,否则,编译无法通过而报错。除非该子类也是抽象类。
理解:假设不重写所有抽象方法,则类中可能包含抽象方法。那么创建对象后,调用抽象的方法,没有意义。
-
abstract可以用来修饰类和方法,不能用来修饰属性和构造方法
接口
- 没有静态代码块和构造方法【不能直接new】!
抽象方法和常量【7】
接口当中的常量,必须进行手动赋值,不能不赋值。
public static 方法名
public static final int NUM = 10;
默认方法、静态方法【8】
默认方法
使用default
修饰,不可省略,public
可省略,有方法体!
作用
- 可以解决接口升级的问题。
- 供子类调用或子类重写。
- 只能通过实现类的对象来调用。
代码如下:
public interface InterfaceName {
public default 返回值类型 方法名称(参数列表) {
方法体
}
}
静态方法
使用static
修饰,供接口直接调用。
注意
-
不能通过接口实现类的对象来调用接口当中的静态方法。
-
因为一个接口类可以实现多个接口,静态方法可能会产生冲突。
代码如下:
public interface InterfaceName {
public static void method2() {
// 执行语句
}
}
私有方法、私有静态方法【9】
私有方法
使用private
修饰,供接口中的默认方法或者静态方法调用。
使用
私有方法:只有默认方法可以调用。
私有静态方法:默认方法和静态方法可以调用。
-
从设计的角度讲,私有的方法是对默认方法和静态方法的辅助。
-
如果一个接口有多个默认方法,并且方法中有重复的内容
-
那么可以抽调出来,封装到私有方法中,供默认方法去调用。
目的
- 解决两个默认方法之间的重复代码问题。
- 这个方法不应该让实现类使用,应该是私有化的
总结
1. 接口中的成员变量其实是常量
格式
[public] [static] [final] 数据类型 常量名称 = 数据值;
注意
- 常量必须进行赋值,而且一旦赋值不能改变。
- 常量名称完全大写,用下划线进行分隔。
2. 接口中最重要的就是抽象方法
格式:
[public] [abstract] 返回值类型 方法名称(参数列表);
注意:
- 实现类必须覆盖重写接口所有的抽象方法,除非实现类是抽象类。
3. 从Java 8开始,接口里允许定义默认方法
格式:
[public] default 返回值类型 方法名称(参数列表) { 方法体 }
注意:
- 默认方法也可以被覆盖重写
4. 从Java 8开始,接口里允许定义静态方法
格式:
[public] static 返回值类型 方法名称(参数列表) { 方法体 }
注意:
- 通过接口名称进行调用,不能通过实现类对象调用接口静态方法
5. 从Java 9开始,接口里允许定义私有方法
格式:
-
普通私有方法
private 返回值类型 方法名称(参数列表) { 方法体 }
-
静态私有方法
private static 返回值类型 方法名称(参数列表) { 方法体 }
注意:
- private的方法只有接口自己才能调用,不能被实现类或别人使用。
接口的多实现
抽象方法重写
如果实现多个接口的抽象方法有重名,只需重写一次
- 爸爸妈妈都让我去上学,说一次就行了!
默认方法重写
接口中,有多个默认方法时,实现类都可继承使用。如果默认方法有重名的,必须进行覆盖重写一次。
- 爸爸让吃西瓜,妈妈让吃雪糕,自己要决定吃什么才行!
静态方法重名不要紧
接口中,存在同名的静态方法并不会冲突,因为只能通过各自接口名访问静态方法。
继承优先于接口实现
若一个类直接父类(亲爹)当中的方法,和接口中的默认方法重名,优先使用父类中的方法。
接口的多继承
一个接口能继承另一个或多个接口,这和类之间的继承比较相似。接口的继承使用extends
关键字,子接口能继承父接口的方法。
如果父接口中的默认方法重名,那么子接口需要重写一次。
多态
是指同一行为,具有多个不同的表现形式
可以使程序编写的更简单,并具有良好的扩展
前提
-
继承或者实现【二选一】
-
方法的重写【意义体现:不重写,无意义】
-
父类引用指向子类对象【格式体现】
使用
编译看左,运行看右
-
编译看左:当使用多态方式调用方法时,首先检查父类中是否有该方法,如果没有,则编译错误;
-
运行看右:如果有,执行的是子类重写后方法,若没重写,执行父类方法。
向上转型
当父类引用指向一个子类对象时,便是向上转型,这个过程是默认的
向下转型
前提
-
父类对象指向的是子类对象,也就是说,在向下转型之前,它得先向上转型
-
向下转型只能转型为本类对象
关键字:animal instanceof Dog
布尔值
final关键字
- 类:被修饰的类,不能被继承,里面的方法不能覆盖重写。
- 方法:被修饰的方法,不能被重写。
abstrct
和final
不能同时使用 - 变量:被修饰的变量,不能被重新赋值。
- 不能修饰构造方法。
修饰变量
局部变量
-
基本类型,要保证数值不变
-
引用类型,要保证地址值不变
成员变量
- 显式初始化:
private final String NAME= "小明";
- 构造方法初始化:保证类当中所有【重载的构造方法】,都最终会对final的成员变量进行赋值
- 不能使用set函数进行赋值
内部类
成员内部类
-
外部类名称.内部类名称 对象名 = new 外部类名称().new() 内部类名称();
-
外部类名称.this.外部类成员变量名
public class Outer {
int num = 10; // 外部类成员变量
public class Inner /* extends Object */ {
int num = 20; // 内部类成员变量
public void methodInner() {
int num = 30; // 内部类方法的局部变量
System.out.println(num); // 局部变量,就近原则 30
System.out.println(this.num); // 内部类的成员变量 20
System.out.println(Outer.this.num); // 外部类的成员变量 10
}
}
}
权限修饰符规则
- 外部类:public / (default)
- 成员内部类:public / protected / (default) / private
局部内部类
定义在一个方法内部
只有当前所属的方法才能使用他,出了这个方法外面就不能用了
访问所在方法的局部变量
局部内部类,若想访问所在方法的局部变量,那么这个局部变量必须是【final修饰】,与生命周期有关
从java8+开始,只要局部变量事实不变,那么final关键字可以省略。
修饰符
定义一个类的时候,权限修饰符规则:
- 外部类:public / (default)
- 成员内部类:public / protected / (default) / private
- 局部内部类:什么都不能写
匿名内部类
- 内部类的简化写法。它的本质是一个带具体实现的父类或者父接口的匿名的子类对象。
- 匿名内部类必须继承一个父类或者实现一个父接口。
可变参数 [5]
可变参数底层就是一个数组,根据传递参数个数不同,会创建不同长度的数组,来存储这些参数
要求
- 一个方法的参数列表,只能有一个可变参数
- 传递的参数个数,可以是0个(不传递),1,2…多个
- 如果方法的参数有多个,那么可变参数必须写在参数列表的末尾
异常
编译时期异常
编写代码报错
运行时期异常
运行时异常被抛出可以不处理。即不捕获也不声明抛出。
抛出异常:throw
- 用在方法内,用来抛出一个异常对象,
- 将这个异常对象传递到调用者处,
- 并结束当前方法的执行
throw new NullPointerException("要访问的arr数组不存在");
声明异常:throws
-
关键字throws运用于方法声明之上
-
用于表示当前方法不处理异常
-
提醒该方法的调用者来处理异常(抛出异常)
-
throws后面可以写多个异常类,用逗号隔开
-
如果抛出的多个异常对象有子父类关系,那么直接声明父类异常即可
try
、catch
- 都不能单独使用,必须连用
finally
- 避免有return语句
父子类异常要求
- 子类抛异常不能大于父类
- 父类未抛出异常,子类只能捕获处理
自定义异常类
- 自定义异常类,必须继承
Exception
或者RuntimeException
API
Random
包路径:java.util.Random
:该类需要import导入使后使用。
构造函数
- 创建一个新的随机数生成器。
public Random();
成员方法
public int nextInt()
:返回一个伪随机数,范围是int的所有范围,有正负。public int nextInt(int n)
:返回一个伪随机数,左闭右开[0,n)
。
String【略】
特点
- 字符串不变:字符串的值在创建后不能被更改。是常量。
String s1 = "abc";
s1 += "d";
System.out.println(s1); // "abcd"
// 内存中有"abc","abcd"两个对象,s1由指向"abc",改变指向了"abcd".
- 因为字符串不可变,所以字符串是可以共享的。
String s1 = "abc";
String s2 = "abc";
// 内存中只有一个"abc"对象被创建,同时被s1和s2共享。
-
"abc"
等效于char[] ch ={'a','b','c'}
字符串效果上相当于是char型字符数组。但是底层原理是 byte[] 字节数组。1 byte = 8 bit
String str = "abc";
- 相当于
char data[] ={'a','b','c'};
String str = new String(data);
StringBuilder:可变字符序列
特点
-
字符串缓冲区,可以提高字符串的效率。
-
底层也是一个数组,但未被
final
修饰,可以改变长度 -
StringBuilder
会自动维护数组的扩容。(默认16字符空间,超过自动扩充)
构造方法
public StringBuilder()
:构造一个空的StringBuilder
容器,初始容量为 16 个字符。public StringBuilder(String str)
:构造一个StringBuilder
容器,并将字符串添加进去。
常用方法
public StringBuilder append(...)
:添加任意类型数据的字符串形式,并返回当前对象自身(this)。public String toString()
:将当前StringBuilder
对象转换为String对象。
System
public static long currentTimeMillis()
:返回以毫秒为单位的当前时间。public static void arraycopy(Object src, int srcPos, Object dest, int destPos, int length)
:将数组中指定的数据拷贝到另一个数组中。
集合
Collection
public boolean add(E e)
: 把给定的对象添加到当前集合中 。public void clear()
:清空集合中所有的元素。public boolean remove(E e)
: 把给定的对象在当前集合中删除。public boolean contains(E e)
: 判断当前集合中是否包含给定的对象。public boolean isEmpty()
: 判断当前集合是否为空。public int size()
: 返回集合中元素的个数。public Object[] toArray()
: 把集合中的元素,存储到数组中。
Iteator迭代器
Iterator it = coll.iterator(); // 取迭代器的实现类对象,使用`Iterator`接口接收(多态)
boolean b = it.hasNext(); // 判断还有没有下一个元素
Object o = it.next(); // 取出集合中的下一个元素
List接口
特点
- 单列集合
- 允许出现重复的元素
- 带有索引的集合
常用方法
public void add(int index, E element)
: 将指定的元素,添加到该集合中的指定位置上。public E get(int index)
:返回集合中指定位置的元素。public E remove(int index)
: 移除列表中指定位置的元素, 返回的是被移除的元素。public E set(int index, E element)
:用指定元素替换集合中指定位置的元素,返回值的更新前的元素。
遍历
- for循环
- 迭代器
- 增强for循环(迭代器简化版)
ArrayList
概念
-
java.util.ArrayList
集合数据存储的底层结构是数组结构。元素增删慢,查找快 -
此实现不是同步的,多线程,速度快
遍历
- 条件:
i < list.size()
LinkedList集合
概述
- 此实现不是同步的,多线程,速度快
特点
-
底层是一个链表结构:查询慢,增删快
-
里边包含了大量操作首尾元素的方法
-
若想使用LinkedList集合特有的方法,不能用多态
Vector集合
- 底层:数组
- 同步:单线程,速度慢。ArrayList逐渐取代了它
Set接口
特点
- 不允许存储重复的元素
- 没有索引,没有带索引的方法,也不能使用普通的for循环遍历
- Set集合取出元素的方式可以采用:迭代器、增强for。普通for不行!
HashSet
优点
- 具有良好的存取和查找性能:
HashSet
是根据对象的哈希值来确定元素在集合中的存储位置。 - 元素唯一性:依赖于:
hashCode
与equals
方法。
特点
- 不允许存储重复的元素
- 没有索引,没有带索引的方法,也不能使用普通的for循环遍历
- 是一个无序的集合,存储元素和取出元素的顺序有可能不一致
- 底层储数据的结构:哈希表(查询的速度非常的快)
存储自定义类型元素
- 必须重写hashCode和equals方法,保证键不重复
LinkedHashSet
在HashSet下面有一个子类java.util.LinkedHashSet
,它是**链表和哈希表(数组+链表/红黑树)**组合的一个数据存储结构。可保证集合元素的有序。
Map
特点
java.util.Map<k,v>集合
- 是一个双列集合,一个元素包含两个值(一个key,一个value)
- 元素
key和value
的数据类型可以相同,也可以不同 - 元素
key
是不可以重复的,value
可以 - 元素
key和value
是一一对应的
常用方法
map.put()
:把指定的键和值添加到Map集合中。
key
不重复,返回值是null
key
重复,会使用新的value
替换map
中重复的value
,并返回被替换的value
值
map.remove()
: 删除指定的键对应的键值对元素,返回被删除元素的值。
- key存在,返回被删除的值
- key不存在,返回 null
map.get()
:在Map集合中获取对应的值
key
存在,返回对应的value
值key
不存在,返回null
map.contains()
:判断集合中是否包含指定的键
- 包含返回true
- 不包含返回false
Entry:键值对对象
Map<String,Integer> map = new HashMap<>();
Set<Map.Entry<String, Integer>> set = map.entrySet();
Iterator<Map.Entry<String, Integer>> it = set.iterator();
while (it.hasNext()) {
Map.Entry<String, Integer> entry = it.next();
String key = entry.getKey();
Integer value = entry.getValue();
System.out.println(key+ ":" +value);
}
HashMap集合
java.util.HashMap<k,v>集合 implements Map<k,v>接口
-
底层是哈希表:查询的速度特别的快
JDK1.8之前:数组+单向链表
JDK1.8之后:数组+单向链表|红黑树(链表的长度超过8):提高查询的速度
-
是一个无序的集合,存储元素和取出元素的顺序有可能不一致
LinkedHashMap集合
是HashMap
的子类
- 底层是哈希表+链表(保证迭代的顺序)
- 是一个有序的集合,保证元素的存取顺序一致
Hashtable
java.util.Hashtable<K,V>集合 implements Map<K,V>接口
与HashMap对比
HashMap 【JDK 1.2才有的】
-
多线程集合,速度快,线程不安全
-
底层是哈希表
-
键和值都可以为空(null),【之前学的所有集合都可为空】
Hashtable 【JDK 1.0】
- 单线程集合,速度慢,线程安全
- 键和值都不允许为空
Hashtable
和Vector
集合一样,在【jdk1.2】版本之后被更先进的集合HashMap,ArrayList
取代- 子类
Properties
集合是一个唯一和IO流相结合的集合
HashMap存储自定义类型键值
前提:保证key唯一
- 必须重写hashCode方法和equals方法
泛型
将数据类型作为参数进行传递
优点:
- 避免了类型转换的麻烦,存储的是什么类型,取出的就是什么类型
- 把运行期异常(代码运行之后会抛出的异常),提升到了编译期(写代码的时候会报错)
弊端:
- 泛型是什么类型,只能存储什么类型的数据
确定泛型:
- 自定义含有泛型的类:在创建对象的时候确定泛型
- 含有泛型的方法:调用方法时,确定泛型的类型
- 含有泛型的接口:定义实现类时,【指定】接口的泛型
- 含有泛型的接口:创建实现类【对象】时,确定泛型的类型
泛型通配符
当使用泛型类或者接口时,传递的数据中,泛型类型不确定,可以通过通配符<?>
表示。
特点
- 不能创建对象使用,只作为方法的参数使用
- 【泛型不存在继承关系】
受限泛型:上限、下限
JDK9对添加集合的优化
当集合中存储的元素的个数已经确定了,不在改变时使用
注意
- of方法只适用于List接口,Set接口,Map接口,不适用于接口的实现类
- of方法的返回值是一个不能改变的集合,集合不能再使用
add、put
方法添加元素,会抛出异常 - Set接口和Map接口在调用of方法的时候,不能有重复的元素,否则会抛出异常
解析
-
of
方法只是Map
,List
,Set
这三个接口的静态方法,其父类接口和子类实现并没有这类方法,比如
HashSet
,ArrayList
等 -
返回的集合是不可变的;增加或删除都不行!!