JAVA SE
1.java跨平台原理
2.功能最小单元-方法
3.注释、字面量、变量、关键字、标识符
注释:// // //***/, javac编译后去掉注释,与执行无关
字面量:程序中能直接书写的数据,”hello”, 1, 3.14, ‘A’, true, false, null,\t,\n
1
2
3
4
5
6
7
8
// 定义整型变量i1,并初始化为二进制值101010
int i1 = 0b101010;
// 定义整型变量i2,并初始化为十六进制值fa
int i2 = 0xfa;
// 定义整型变量i3,并初始化为八进制值12
int i3 = 012;
变量:代表内存地址,
变量类型:
数据类型 | 默认值 | 大小 |
---|---|---|
boolean | false | 不确定 |
char | ‘\u0000’ | 2 字节 |
byte | 0 | 1 字节 |
short | 0 | 2 字节 |
int | 0 | 4 字节 |
long | 0L | 8 字节 |
float | 0.0f | 4 字节 |
double | 0.0 | 8 字节 |
整数字面量默认使用int类型
浮点字面量默认使用double类型
关键字:java内置的语法修饰词
标识符:自定义的名称,用于变量名,类名、方法名
一般由数字字母下划线和$组成
不能以数字开头,不能是关键字,不能包含一些特殊字符(%,&,#,…)
变量名:小驼峰
类名:大驼峰
4.方法(method/function)
方法是功能的基本单元
格式:修饰符 返回值 方法名(参数列表){
// 方法体
return 返回值;
}
1
2
3
4
// 定义一个方法,求两个数的和
public static int getSum(int a, int b) {
return a + b;
}
方法是否需要接受数据?
方法是否需要返回数据?无返回值,返回void
重载方法:一个类中,出现多个方法名称相同,但是他们的形参列表不同,那么这些方法就称为重载方法。
System.out.println()就是重载方法
return; 用于无返回值的方法中提前结束方法
5.类型转换
自动类型转换:类型范围小的变量,可以直接赋值给类型范围大的
byte–>short–>int–>long–>float–>double
char–>int
强制类型转换:大–>小
类型范围大数据类型不能直接转换成小的类型,因为可能造成窄化时数据损失,需要使用强制类型转换符
1
2
3
4
int b = 12;
byte j = (byte) b;// 强制转换
print3(j);
public static void print3(byte a) {}
表达式的自动类型转换:在表达式中,小范围类型变量会自动转换成表达式中大范围的类型,再参与运算。
byte、short、char–>int–>long–>float–>double
表达式结果最终类型是由最高类型决定
byte、short、char是直接转换成int类型参与运算的。
byte + byte的结果是int
6.输入/输出
输入:调用Scanner的API
1
2
3
4
5
6
Scanner scanner = new Scanner(System.in);
System.out.println("请输入年龄:");
int age = scanner.nextInt();
System.out.println("请输入姓名:");
String name = scanner.next();
System.out.println("年龄:" + age + ",姓名:" + name);
7.运算符
+ - * / %
+: 加;连接。能加就加,不能加就连接
++/–:自增运算符
赋值运算符
= += -= *= /= %=
1
2
3
4
byte b1 = 10;
byte b2 = 20;
b1 += b2; // 等价于 b1 = (byte) (b1 + b2) +=自带强制类型转换
System.out.println(b1);
关系运算符:
> < >= <= == !=
运算的结果为boolean值
三元运算符
boolean表达式 ? 为true时执行的语句 : false时执行的语句
1
String result = a % 2 == 0 ? "偶数" : "奇数";
逻辑运算符
与:& or &&(短路与,左边为false, 就不执行右边的表达式了)
或: | or | (短路或,左边为true,就不执行右边的表达式) |
非:!
异或:^
8.程序控制流程
分支结构 if-else 和switch-case 根据条件真假,决定执行不同代码
if的三种形式
1
2
3
if(condition) {}
if(condition) {} else {} // 非此即彼
if(condition) {} else if(condition2) {} [else]
switch: 通过比较值是否相等,来决定执行那条分支
if在功能上比switch强,if可以进行区间判断
switch表达式类型只能是byte short int char 枚举 String 不支持float double(小数,java这些类型不精确),long
case给出的值不允许重复,且只能是字面量(常量),不能是变量。
正常使用switch时,一定要写break,否则会出现穿透现象。
合理利用穿透可以简少冗于代码
循环结构
for
while
功能与for一致
知道 循环次数用for,不知道用while
do-while 先执行后判断,至少执行一次
死循环
1
2
3
while (true) {}
for (; ; ) {}
do{} while(true);
continue: 跳过本次循环
break: 结束循环
9、数组
程序中数据存储:变量只能存储一个变量
数组:是一个数据容器,可以用来存储一批同 类型的数据
静态初始化数组
1
2
3
4
// 定义一个数组,存储10个名字
// 静态初始化数组,定义时已经确定数组的长度
String[] names = {"张三", "李四"};
String[] names2 = new String[]{"张三", "李四"};
动态初始化数组
1
2
3
// 数组动态初始化
// 只确定数组的类型和长度,不指定具体的值
double[] scores = new double[8]; // 声明后默认值是0.0
动态初始化数组的默认值规则
byte short char int long: 0
float double: 0.0
boolean: false
引用类型:类,接口,数组,String:null
访问数组中的元素
1
2
3
// 随机获取一个索引值
int index = (int) (Math.random() * names.length);
String name = names2[index];
数组的遍历:求和,搜索,求最值
打乱顺序(洗牌)
1
2
3
4
5
6
7
8
for (int i = 0; i < pokers.length; i++) {
// 生成一个随机索引,范围在0到扑克牌数组长度之间
int index = (int) (Math.random() * pokers.length);
// 交换:将当前元素与随机索引处的元素交换位置。
String temp = pokers[i];
pokers[i] = pokers[index];
pokers[index] = temp;
}
二维数组:
二维数组的元素是一维数组
1
2
3
4
5
6
7
8
9
10
11
// 静态初始化
// 动态初始化
int[][] arr2 = new int[2][3];
arr2[0] = new int[]{1, 2, 3};
arr2[1] = new int[]{4, 5, 6};
// 遍历
for (int i = 0; i < arr.length; i++) {
for (int j = 0; j < arr[i].length; j++) {
System.out.print(arr[i][j] + " ");
}
}
二维数组洗牌
1
2
3
4
5
6
7
8
9
10
for (int i = 0; i < arr.length; i++) {
for (int j = 0; j < arr[i].length; j++) {
int r = (int) (Math.random() * arr.length);
int c = (int) (Math.random() * arr[i].length);
// 交换:将当前元素与随机索引处的元素交换位置
int temp = arr[r][c];
arr[r][c] = arr[i][j];
arr[i][j] = temp;
}
}
10.面向对象编程
对象:一种特殊的数据结构:成员变量(状态)+方法(行为)
设计对象:1.设计对象的模板类,2通过new关键字获取具体的对象
jvm中对象 :划分为栈内存、堆内存、方法区
万物皆对象,谁的数据谁存储
构造器:特殊的方法:没有返回值,方法名和类名相同
创建对象时,对象会去调用构造器
1
Student student = new Student();
作用:创建对象时,同时完成对象成员变量的初始化赋值
类默认就自带一个无参构造器,但如果自定义了有参构造器则该无参构造器将被覆盖,如果还想使用无参构造器,则必须显式声明。
this关键字:指代当前对象,哪个对象调用这个方法,this就拿到哪个对象
可以用于解决成员变量名字与类中方法局部变量名冲突问题: this.variable_name = variable_name
封装:类就是一种封装
封装设计要求:合理隐藏,合理暴露
1.合理隐藏:private 关键字修饰成员变量,就只能在本类中被直接访问,其他地方不能访问。
2.合理暴露:使用public修饰的getter和setter方法合理访问成员变量的取值和赋值
javabean: 类中成员变量全部私有,并提供public修饰的getter和setter方法,提供无参构造器
实体类的应用:实体类的对象只负责数据存储,而对数据的业务处理交给其他类对象来完成,以实现数据和操作的分离
static关键字:可以修饰成员变量、成员方法
静态变量:有static 修饰的成员变量,属于类,只有一份,会被类的所有对象共享
实例变量:无static修饰,属于具体对象私有,每个对象都有一份
静态变量的应用场景:如果数据只需要一份,且希望能够被共享(访问,修改),则该数据可以定义成静态变量来记住。
记录某类创建了多少次,可以把静态变量count的自增写在构造器中
静态方法(函数):static修饰的成员方法,属于类
实例方法:无static修饰的成员方法,属于对象。
什么时候使用静态方法:如果这个方法只是为了做一个功能,并且不需要直接访问对象的数据,这个方法直接定义成静态方法。如果这个方法是对象的行为,需要访问对象的数据,这个方法必须定义成实例方法。
静态方法的常用场景
工具类 设计:xxxUtil,私有化构造器,静态方法。
注意事项: 静态方法可以访问静态变量,不能访问实例变量。
实例方法可以访问静态变量,也可以访问实例变量。
实例方法中可以出现this关键字,静态方法中不可以出现。
继承
提高代码复用性
extends关键字:建立两个类之间的继承关系
子类能继承父类的非私有成员(成员变量、方法)
继承后对象的创建:f子类的对象是由子类、父类共同完成的。
权限修饰符:限制类中成员(成员变量,方法,构造器)能够被访问的范围。
private(只能本类)< default(本类和同包下) < protected(本类,同包,子孙类中) < public(任意位置)
继承特点:
java是单继承:一个类只能继承一个直接父类,java不支持多继承,但支持多层继承,Java中所有类都是Ojbect类的子类,就近原则:优先访问自己类中,自己类中没有才会访问父类
如果想访问父类中和子类中同名的成员,可以使用super.成员
方法重写:子类写了一个方法,形参列表与父类方法一样的覆盖了父类的方法,子类调用该方法,而不是原始的父类方法。
规范:声明不变,重新实现。
note: 子类重写父类方法时,访问权限大于或者等于父类,不能造成父类方法可以调用,子类重写的方法不能调用
重写方法的返回值类型,必须与被重写的父类方法的返回值类型一样,或者是其子类
私有方法(私有方法不能被继承,所以不能被重写),静态方法不能被重写。
子类构造器:子类的 全部构造器,都会调用父类的构造器,再执行自己。
默认情况下,子类的全部构造器的第一行代码都是super(),写不写都有,它会调用父类的无参数构造器。
如果父类没有无参构造器,则我们必须在子类构造器的第一行手写super(…),指定去调用父类的有参构造器。
super(…)调用父类的有参构造器的目的:为对象中包含父类这部分的成员变量进行赋值。
this(…)调用兄弟构造器:代码复用
this和super都只能放在第一行,所以二者不能同时出现在第一行。
多态
多态是在继承/实现情况下的一种现象,表现为:对象多态、行为多态。
成员方法:编译看左边,运行看右边
成员变量:编译看左边,运行看左边
多态的前提:有继承/实现关系,存在父类引用子类对象,存在方法重写
多态的注意事项:多态是对象、行为的多态,java中的属性(成员变量)没有多态
多态的好处:在多态形式下,右边的对象是解耦合的,更便于扩展和维护;
定义方法时,使用父类类型的形参,可以接受一切子类对象,扩展性更强,更便利。
1
Animal a = new Dog();
多态的缺点:多态不能调用子类独有的功能,要解决此问题,需要向下转型(强制类型转换)
多态下的类型转换
1
2
3
4
5
6
// 自动类型转换
Animal a = new Dog();
// 强制类型转换
Dog d = (Dog) a;
// 乌龟才有的游泳方法
d.swiming();
在强制转换前,先用instanceof判断是否为要转的类型,避免出现运行时ClassCastException
final关键字:可以修饰类、方法、变量。
修饰类:类不能被继承了。
修饰方法:方法不能被重写乐。
修饰变量:该变量只能被赋值一次。
常量:final修饰的静态变量,常用于系统的配置信息。
代码可读性更好,可维护性也更好.
程序编译后,常量会被“宏替换”:出现常量 的地方全部会被替换成字面量,这样保证了使用常量和直接使用字面量的性能是一样的。
note:final修饰基本数据类型变量,变量存储的数值不能改变
final修饰的引用类型变量,变量存储的地址不能被改变,但是地址所指向对象的内容是可以改变的
单例类(设计模式):作用:确保某个类只能创建一个对象。
实现步骤:1.私有构造器,定义一个类变量记住类的一个对象,定义一个类方法,返回对象。(饿汉式)
1
2
3
4
5
6
7
public class A {
private A() {}
private static A instance = new A();
public static A getInstance() {
return instance;
}
}
懒汉式:用的时候,才开始创建对象。步骤:私有构造器,定义一个静态变量存储对象,提供一个静态方法,保证返回的是同一个对象。
1
2
3
4
5
6
7
8
9
10
public class B {
private static B instance;
private B(){}
public static B getInstance() {
if (instance == null) {
instance = new B();
}
return instance;
}
}
枚举类
1
2
3
public enum A {
X,Y,Z;
}
反编译后代码:
1
2
3
4
5
6
7
8
public final class A extends java.lang.Enum<A> {
public static final A X;
public static final A Y;
public static final A Z;
public static A[] values();
public static A valueOf(java.lang.String);
static {};
}
枚举类都是最终类,不能被继承,枚举类的父类是java.lang.Enum
枚举类的第一行只能罗列一些名称,这些名称都是变量,并且每个变量都会记住枚举类的一个对象
枚举类的构造器都是私有的,因此枚举类对外不能创建对象
枚举类很适合做信息分类和标志
抽象类:
abstract关键字:修饰类就是抽象类,修饰方法就是抽象方法
抽象类中不一定要有抽象方法,但是抽象方法一定在抽象类中。
抽象类和普通类一样可以有:成员变量,成员方法,构造器。
抽象类不能创建对象,仅作为一种特殊的父类,让子类继承并实现方法。
有得有失:得到了抽象方法的能力,失去了创建对象的能力,
抽象类的使命就是被子类继承。
一个类继承抽象类,必须重写所有的抽象方法或者该类也定义为抽象类 。
使用抽象类的 好处:强制要倪去实现抽象的方法。感觉有点多余,就是为了多加一个抽象方法。
模板方法设计模式:提供一个方法作为完成某个功能的模板,模板方法封装了每个实现步骤,但允许子类提供特定步骤的实现:
1.定义一个抽象类
2.在里面定义2个方法:一个是模板方法:把共同的步骤放到里面去。一个是抽象方法:不确定的实现步骤,交给具体的子类来完成。
建议:用final来修饰模板方法。
1
2
3
4
5
6
7
8
9
public abstract class People {
public final void write() {
System.out.println("固定流程1");
System.out.println("固定流程2");
writeMain();
System.out.println("固定流程3");
}
public abstract void writeMain();
}
接口:
interface关键字:定义接口 。
jdk8之前接口中只可以写:常量(static final)、抽象方法。
接口不能创建对象。
接口中的成员默认是public的
接口是用来被实现(implements)的,实现接口的类被称为实现类,一个 类可以同时实现多个接口。
借口的好处:弥补了类单继承的不足,一个类可以实现多个借口,使类的角色更多,功能更强大;让程序可以面向接口编程,更利于程序的解耦合
jdk8之后接口新增了三种形式的方法(子类不用强制实现):增强了接口的能力
默认方法:使用default修饰,使用实现类的对象调用
1
2
3
default void go() {
System.out.println("========");
}
私有方法(jdk9):只能在借口内部被调用
1
2
3
private void run() {
System.out.println("runnnnnnnnnnnnnnnn...");
}
类/静态方法:必须用接口名.方法名调用
1
2
3
static void show() {
System.out.println("show...");
}
接口的注意事项:
1.接口与接口可以多继承:一个接口可以同时继承多个接口
类与类:单继承,一个类只能继承一个直接父类
类与接口:多实现,一个类可以实现多个接口
2.一个接口继承多个接口,如果多个接口中存在方法签名冲突,则此时不支持多继承,也不支持多实现。
1
2
3
4
5
6
7
8
9
interface A{
void go();
}
interface B{
String go();
}
interface C extends A,B{
}
3.一个类继承了父类,同时又实现了接口,如果父类和接口中有同名的方法,实现类会优先使用父类的方法
4.一个类实现了多个接口,如果多个接口中存在同名的默认的方法,可以不冲突,只要这个类重写该方法即可
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
interface A{
default void go() {
System.out.println("A go");
}
}
class Father {
void go() {
System.out.println("Father go");
}
}
class Son extends Father implements A{
@Override
public void go() {
A.super.go(); // 在默认继承父类go方法的情况下,调用父接口的方法
super.go();
}
}
抽象类、接口的区别和对比
相同点:都是抽象形式,都可以有抽象方法,都不能创建对象。
都是派生子类形式:抽象类是被子类继承使用,接口是被实现类实现
都能支持多态
不同点:抽象类中可以定义普通类的全部普通成员,接口只能定义常量,抽象方法
抽象类只能被单继承,接口可以被类多实现
一个类继承抽象类就不能再继承其他类,一个类可以实现多个接口
抽象类体现模板思想,更利于做父类 ,实现代码的复用性 最佳实践
接口更适合做功能的解耦合 最佳实践
代码块:是类的五大成分之一(成员变量、构造器、方法、代码块、内部类)
代码块分为静态代码块、实例代码块。
静态代码块:类加载时自动执行,由于类只会加载一次,所以静态代码块也只会执行一次。
作用:完成类的初始化,如:对静态变量的初始化赋值。
实例代码块:
特点:每次创建对象时,执行实例代码块,并在构造器前执行。
作用:和构造器一样,都是用来完成对象的初始化的。如:对实例变量进行初始化赋值。
内部类:如果一个类定义在另一个类内部,这个类就是内部类。
成员内部类:就是类的一个普通成员
1
Outer.Inner inner = new Outer().new Inner();
可以直接访问外部类的实例成员、静态成员
可以拿到当前外部类对象,格式:外部类名.this
静态内部类:有static修饰的内部类,属于外部类自己持有。
1
Outer.inner inner = new Outer.inner();
可以直接访问外部类的静态成员,不能直接访问外部类的实例成员
局部内部类:是定义在方法中,代码块中,构造器中等…..
匿名内部类:是一种特殊的局部内部类;匿名:不需要为这个类命名,默认有个隐藏的名字
匿名内部类本质就是一个子类,并立即创建出一个子类对象,匿名内部类实际上是有名字的:外部类名$编号数字.class
1
2
3
4
5
6
Animal a = new Animal() {
@Override
public void cary() {
System.out.println("我是一个匿名内部类");
}
};
反编译后:
1
2
3
4
5
6
7
8
class Test$1 extends Animal {
Test$1() {
}
public void cary() {
System.out.println("我是一个匿名内部类");
}
}
作用:用于更方便的创建一个子类对象
常见形式:通常作为一个对象参数传输给方法。
函数式编程:可以Lambda函数替代某些匿名内部类对象,从而让程序更简洁
lambda表达式:jdk8新增的语法形式,表示函数。
(被重写的方法形参列表) -> { 被重写的方法的方法体}
lambda只能替代函数式接口的匿名内部类
函数式接口:只有一个抽象方法的接口,可以加上@FunctionalInterface标记
方法引用:
静态方法引用:类名::静态方法,在 -> 前后的参数形式一致时可以使用方法应用
实例方法引用:对象名::实例方法,与静态方法类似
特定方法引用:
1
2
3
4
5
6
// 目标:特定类型的方法引用
// 需求:有一个字符串数组,里面有一些人员名,要求按照姓名的首字母
String names[] = {"Tom", "Jerry", "Lucy", "Mary", "Alice","曹操", "andy", "chris" };
Arrays.sort(names, (s1, s2) -> s1.compareToIgnoreCase(s2));
Arrays.sort(names, String::compareToIgnoreCase);
System.out.println(Arrays.toString(names));
构造器引用:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public static void main(String[] args) {
// CarFactor cf = name -> new Car(name);
CarFactor cf = Car::new; // 构造器引用
Car c1 = cf.getCar("奔驰");
}
interface CarFactor {
Car getCar(String name);
}
@Data
@AllArgsConstructor
@NoArgsConstructor
class Car {
private String name;
}
String API
String创建字符串的对象的方式
方式一: String name = “abc”
方式二:构造器
二者的区别:
只要是以第一种”hello”的方式创建的字符串对象放在常量池中,相同内容只放一个
1
2
3
4
5
6
String s1 = "hello";
String s2 = "hello";
System.out.println(s1 == s2); // true
String s3 = new String("hello");
System.out.println(s1 == s3); // false
String 常用方法
比较相等时使用equals方法,不要使用==方法,==比较的是地址,==为true表示是同一个对象
集合:集合是一种容器,用来装数据的,类似于数组
为什么使用集合?数组大小固定,集合长度可变。
ArrayList:创建对象,增、删、改、查
GUI编程
GUI:Graphical User Interface,图形用户界面。
java的gui包
awt(Abstract window tookit) 提供了一组原生的gui组件,依赖于操作系统的本地窗口系统
swing:基于awt,提供了更丰富的gui组件,轻量级组件,不依赖于本地窗口系统
常用的Swing组件:
JFrame:窗口
JPanel:用于组织其他组件的容器
JButton: 按钮组件
JTextField: 输入框
JTable:表格
布局管理器(Layout Manager)
FlowLayout:水平布局管理器
BorderLayout:东南西北中
GridLayout:网格布局管理器
BoxLayout:盒子布局管理器
常用的事件监听器
点击事件监听器 ActionListener
按键事件监听器 KeyListener
事件的几种常见的写法: 1.提供实现类,2直接使用匿名内部类的对象,3自定义窗口