文章目录
一、构造方法
-
方法名和类名一致,没有void,没有具体的返回值类型。
-
构造方法支持重载
-
注意事项
1. 系统默认提供无参构造方法。 2. 如果写了有参构造方法,系统就不会自动生成无参构造方法。
-
成员变量的赋值方法
- setXXX(参数)赋值
- 有参构造器赋值
-
构造方法私有化后,使成员方法静态化(加入static),直接用 类名.方法名 调用。方便使用。(如工具类就是如此)
工具类
import java.util.Arrays; public class Tools { //私有化构造方法,使外部方法无法new对象,只能使用类名.方法名调用 private Tools() { } //构造方法私有化后,要想使用成员方法,必须将成员方法静态化,使其在类加载时加载 //加法 public static int sum(int... nums) { int temp = 0; for (int i = 0; i < nums.length; i++) { temp += nums[i]; } return temp; } //减法 public static int sub(int... nums) { int temp = 0; for (int i = 0; i < nums.length; i++) { temp = nums[0]; temp -= nums[i]; } return temp; } //乘法 public static int mult(int... nums) { int temp = 1; for (int i = 0; i < nums.length; i++) { temp = nums[i] * temp; } return temp; } //除法 public static double divsion(int... nums) { double temp = -1; boolean flag = true; for (int j = 0; j < nums.length; j++) { if (nums[j] == 0){ flag = false; break; } } for (int i = 0; i < nums.length; i++) { if (flag){ temp = nums[0]; temp /= (double)nums[i] ; } } return temp; } //冒泡排序 public static void bubble(int[] arr) { for (int i = 0; i < arr.length - 1; i++) { for (int j = 0; j < arr.length - 1 - i; j++) { if (arr[i] < arr[i + 1]) { int temp = arr[i]; arr[i] = arr[i + 1]; arr[i + 1] = arr[i]; } } } System.out.println(Arrays.toString(arr)); } }
测试类
public class ToolsTest { public static void main(String[] args) { //加法 System.out.println("加出的结果是:"+Tools.sum(1,2,3)); //减法 System.out.println("减出的结果是:"+Tools.sub(12,2,2)); //乘法 System.out.println("乘出的结果是:"+Tools.mult(3,4,5)); //除法 System.out.println("除法出的结果是:"+Tools.divsion(3,0)); //冒泡排序 int[] arr = {12,34,45,65,6,66,76,77,8,785}; Tools.bubble(arr); } }
二、类中的成员
-
标准类
成员变量 成员方法 构造方法 无参构造方法(都给) 有参构造方法(视情况给出)
-
成员变量
类中的变量
三、static
-
被static修饰符的变量及方法 被称为类成员,随着类的加载而加载。
-
优先于对象存在。也就不能与this共存(this依赖于对象存在)。
-
static能体现共享、共用的含义,如果需求中有’共用’的含义,这个变量直接使用static修饰。
-
被static修饰的成员(变量/方法)访问方式:
- 类名.变量名 类名.方法名 推荐使用
- 对象名.变量名 对象名.方法名 不推荐使用
-
非静态的方法既可以访问静态的,也可以访问非静态的方法。
静态的方法只能访问静态的方法。
四、代码块
-
静态代码块
类一加载,静态代码块先执行,类只加载一次,静态代码块也只加载一次。
静态代码块>局部代码块>构造方法
static { } 1. 位置:类的成员位置 2. 作用: 3. 应用:读取配置文件、完成核心文件的加载
因为类只加载一次,所以static代码块也只加载一次。
-
构造代码块
优先级:构造代码块>构造方法
每创建一个对象,就执行一次构造代码块。
1. 在类成员的位置 如果类中有,先执行构造代码块,再执行构造方法。 2. 可以将构造方法中共性的内容,提取到代码块中。
-
局部代码块
作用:限定某个变量的生命周期
-
加载顺序:
静态代码块>构造代码块>构造方法
五、继承
写父类时,所有都显式给出无参构造方法
子类所有构造方法,都默认访问父类的无参构造方法
-
概念
将多个子类的共性内容,抽取到一个独立的类中,多个类和独立类产生的一种关系称为继承
-
继承的三种类型
-
特点(好处):
- 提高了代码的复用性
- 提高了代码的可维护性
- 是多态的前提条件
-
弊端
继承关系存在局限性,继承的父类方法可能不完全用到。造成耦合度变高。
-
注意事项
- 子类只能继承父类非 私有成员,私有成员,可间接访问。
- 构造方法不能继承,只能间接访问
-
继承的成员变量的访问:
- 子类继承父类,成员变量名不一致,分别访问即可
- 子类继承父类,成员变量名一致,访问采用就近原则
- 首先在子类的局部位置找
- 在子类的成员位置找
- 在父类的成员位置找
- 父类没有,继续往上找,如果没有,则报错。
-
继承的构造方法访问:
- 子类所有构造方法默认访问,父类的无参构造方法。
- 子类的所有构造方法的第一句默认都是super(),可以不写。
-
继承的成员方法的访问:
- 成员方法名不一致,分别调用即可
- 成员方法名一致,而且一模一样,则方法重写。重写的时候必须要保证它的访问权限足够大。
六、Student s = new Student() 完成的事情
- 加载类
- 开辟栈内存空间Student s
- 申请堆内存空间,进行系统默认初始化(通过无参构造方法)
- 初始化完毕,产生堆内存空间地址
- 将堆内存空间地址赋值给栈内存变量s
- 栈内存变量s指向堆内存地址。
七、成员变量和静态变量的区别
存储位置不同:
成员变量:堆内存中
静态变量:static静态区中
生命周期不同:
成员变量:随着对象的创建而存在,随着对象的创建完毕等待垃圾回收而消失(不会立即回收)
静态变量:随着类的加载而存在,随着类的加载完毕而消失(非自定义常量)
初始化不同:
成员变量:可以不初始化,存在默认初始化,通过setXXX(xx)或者有参构造方法显示初始化
静态变量:可以不初始化,或者直接初始化,可可以通过类名.变量名=赋值。
访问方式不同:
成员变量:创建对象访问
静态变量:使用类名.变量名访问
八、super
-
表示父类的空间标识
//访问父类属性 super.父类变量名 //访问父类方法 super.方法名() //访问父类构造方法 super()
九、override 重写
-
概念
子类中出现了和父类中一模一样的方法声明,子类将父类方法覆盖,实现自己的方法,也被称为方法覆盖,方法复写。
-
注意事项
- 父类中私有方法不能被重写
- 子类重写父类方法时,访问权限不能更低
- 父类静态方法,子类也必须通过静态方法进行重写。(算不上方法重写)
-
不想让子类重写方法可以在方法中加入final关键字。
十、final
-
表示最终的,不能被重写
-
final常和static一起使用。
如:public static final int x = 100;
表示常量,无法修改(重新赋值)
-
编译时期常量:jvm不需要加载
-
运行时期常量:jvm需要加载,引用类型都需要加载.
-
作用
-
用来修饰一个引用
如果引用为基本数据类型,则该引用为常量,该值无法修改;
如果引用为引用数据类型,比如对象、数组,则该对象、数组本身可以修改,但指向该对象或数组的地址的引用不能修改。
如果引用是类的成员变量,则必须当场赋值,否则编译会报错。
-
用来修饰一个方法
当使用final修饰方法时,这个方法将成为最终方法,无法被子类重写。但是,该方法仍然可以被继承。
-
用来修饰类
当用final修饰类时,该类成为最终类,无法被继承。简称为“断子绝孙类”。
-
十一、this和super的区别
this:代表的当前类对象的地址值引用
super:代表父类的空间标识 (父类的对象的地址值引用)
使用不一样:
this.变量名 : 访问本类的成员变量
super.变量名: 访问父类的成员变量
this.方法名() ; 访问本类的成员方法
super.方法名(); 访问父类的成员方法
this() :访问本类的无参构造方法
super():访问父类的无参构造方法
this(xx): 访问本类的有参构造方法
super(xx):访问父类的有参构造方法
十二、 方法重写和方法重载的区别
-
方法重载Overload
定义方法的时候,多个方法的方法名相同,参数列表不同,与返回值无关.
-
方法重写Override
在继承中,子类出现了和父类一模一样的方法声明,子类会将父类的方法覆盖,使用子类自己的一些功能.重写的时候要保证访问权限足够大.
-
Overload和Override没有关系
十三、多态
-
概念:
能够体现事物的不同形态(程序中,内存变化)
-
向上转型
父类名 对象名 = new 子类名();(向上转型)
-
向下转型
子类名 对象名 = (子类名)父类引用;
-
多态的条件
-
必须要有继承关系
-
必须存在方法重写
-
必须存在父类引用,指向子类对象
父类名 对象名 = new 子类名();
-
-
多态的成员访问特点
父类名 对象名 = new 子类名();(向上转型);
- 成员变量:编译看左边,运行看左边
- 成员方法:编译看左边,运行看右边(非静态,静态方法跟类有关,不算重写,不构成多态)
- 构造方法:由于存在继承,构造方法在执行的时候,分层初始化,先是父类初始化,再是子类初始化。
-
多态的好处
- 可以提高代码的拓展性
- 可以提高代码的复用性
- 可以提高代码的可维护性
-
多态的弊端
- 无法访问子类的特有方法
解决办法:向下转型
-
向下转型的弊端
使用不当可能出现运行时异常java.lang.ClassException。
十四、abstract(抽象)
-
有抽象方法的类,一定是从抽象类。抽象类不一定有抽象方法。
-
abstract的冲突
- 不能和private一起用。private修饰的方法只能在本类使用,而abstract修饰的方法必须在子类重写。
- 不能和final一起用。final修饰的方法/类(断子绝孙类),无法被重写与继承。
- 不能和static一起用。static修饰的方法,不能算重写。
-
抽象方法:只有方法声明,无方法体
public abstract void show();
抽象方法及抽象类的特点:
-
特点:
-
抽象类不能实例化(不能new 创建对象)
-
抽象类的子类如果也是抽象类,不能实例化,一定会提供最具体的子类,完成实例化,否则无意义。
-
抽象方法必须被子类重写
-
-
-
抽象类的成员特点:
抽象类多态 格式: 抽象的父类名 对象名 = new 具体子类名();
-
成员变量
既可以是变量,也可以是常量
-
成员方法
既可以是抽象方法(强制重写),也可以是普通方法
-
构造方法
可以是无参,也可以是有参。
-
-
一个类没有任何的抽象方法,但是还是定义为抽象类,是为了不让外界直接创建对象。
十五、interface 接口
-
接口是一种特殊的抽象类
-
概念:一系列方法的声明,是一些方法特征的集合
-
命名:遵循大驼峰命名法
-
特点:
-
接口的方法不能有方法体,只能是抽象方法。隐藏 public abstract 可以不写。
-
接口不能实例化(创建对象)
-
如果接口的实现类是一个抽象类(不能实例化),肯定有一个具体的实现类来进行实例化(new对象)
接口多态: 接口名 对象名 = new 具体的子实现类();
-
-
接口的成员特点
- 成员变量: 只能是常量,定义变量时,存在默认修饰符 public static final
- 成员方法:只能是抽象方法,存在默认修饰符 public abstract
- 构造方法:接口没有构造方法(接口不能实例化,自然也就没有构造方法)
-
接口和抽象类的区别
-
成员的区别
-
抽象类
- 成员变量:可以是常量,也可以是变量
- 成员方法:可以是抽象,也可以是非抽象
- 构造方法:可以是有参,也可以是无参
-
接口
- 成员变量:只能是常量,默认修饰符 public static final
- 成员方法:只能是抽象方法 默认修饰符 public abstract
- 构造方法:没有构造方法
-
-
关系的区别
- 类与类:继承关系,只支持单继承
- 类与接口:实现关系(implement)一个类在继承另一个类的同时,还可以实现多个接口
- 接口与接口:继承关系 extends
-
设计理念的区别
- 抽象类不能实例化,核心设计理念:is a 的关系
- 接口不能实例化,核心设计理念:like a的关系
-
十六、Package (包)
- 本质是文件夹(目录)
- 开发中,公司域名反写,多个包用.隔开
- 目的:为了维护代码结构
十七、权限修饰符
十八、形式参数问题
-
类
- 具体类
- 实际参数需要传递当前类对象
- 抽象类
- 实际参数需要传递抽象类的具体子类对象(抽象多态)
- 具体类
-
接口
接口不能实例化,实际参数需要传递接口的子实现类对象(接口多态)
十九 、返回值问题
-
返回基本类型
-
引用类型
-
类
-
具体类
需要返回当前类的对象
-
抽象类
需要返回当前抽象类的子类对象
-
-
接口
-
数组
-
二十、类与类,类与接口、接口与接口的关系
-
类与类:只支持单继承,但是可以多层继承
-
类与接口:实现关系,一个类继承另一个类的同时,可以实现多个接口。
public interface A { } interface B{ } class A1 { } class B1 extends A1 implements A,B{ }
-
接口与接口:不仅可以单继承,也可以多继承
public interface A { } interface B{ } interface C extends A,B{ }
二十一、内部类
-
格式
class Outer{ //成员内部类 class Inner{ } public void show(){ //局部内部类 class Inner1{ } } }
-
成员内部类可以访问外部类的成员,包括私有相关的。
-
成员内部类的访问方式
-
间接访问
-
直接访问
外部类名.内部类名 对象名 = new 外部类名().new 内部类名();
-
-
成员内部类 可以被static修饰
-
静态的成员内部类只能访问,外部类的静态成员
-
静态的成员内部类中无论是静态方法还是非静态方法:访问外部类的成员必须静态
-
想直接通过外部类来访问静态成员内部类的成员信息,访问格式:
外部类名.内部类名 对象名 = new 外部类名.内部类();
-
-
局部内部类
1. 外部类和内部类无继承关系 2. 可以访问外部类的成员,包括私有 3. 访问方式: 1. 在内部类所在的方法中创建内部类对象,创建外部类对象调用成员方法即可 2. 匿名内部类访问
-
匿名内部类
1. 格式 new 抽象类名或接口名(){ //重写方法 }; new 抽象类名或接口名(){ //重写方法 }.方法名(); 2. 匿名内部类的本质 继承了该抽象类,或实现了该接口的子类对象。 3. 应用范围:在局部位置使用(方法定义中或者声明上) 4. 当接口或抽象类中有多个抽象方法时,可以给匿名内部类命名。如eg1 5. 可以解耦,不用创建接口或抽象类的子实现类对象。如eg1 6. 开发中的应用 1. 使用匿名内部类替代,接口或抽象类的子实现类对象。如eg2
eg1:
interface A{ void show(); void show1(); } class Outer{ public void function(){ //没有给匿名内部类命名是,如果有多个抽象方法,调用不方便 new A(){ @Override public void show() { System.out.println("show"); } @Override public void show1() { System.out.println("show1"); } }.show(); new A(){ @Override public void show() { System.out.println("show"); } @Override public void show1() { System.out.println("show1"); } }.show1(); //改进:给匿名内部类命名,通过对象名调用 A a = new A() { @Override public void show() { System.out.println("show 命名匿名内部类"); } @Override public void show1() { System.out.println("show1 命名匿名内部类"); } }; a.show(); a.show1(); } } public class InnerClassDemo { public static void main(String[] args) { Outer outer = new Outer(); outer.function(); } }
eg2:
//抽象类
abstract class Person {
public abstract void work();
}
//定义PersonDemo类
class PersonDemo {
public void show(Person p) {//引用类型--抽象类---需要抽象类子类对象
p.work();
}
}
//定义一个类(具体类),继承Person
class Progammer extends Person {
@Override
public void work() {
System.out.println("程序员日日夜夜敲代码...");
}
}
//测试类
public class ArgsDemo {
public static void main(String[] args) {
//调用PersonDemo类里面的show方法
PersonDemo pd = new PersonDemo();
//Person p = new Person() ;//抽象类不能new
//抽象类多态
Person p = new Progammer();
pd.show(p);
System.out.println("--------------------------------------");
//方式2:可以使用抽象类的匿名内部类
/**
* new 抽象类名(){
* 重写方法
* }
*/
pd.show(new Person() {
@Override
public void work() {
System.out.println("人都需要工作...");
}
});
}
}
二十二、常用类
-
Object类
-
getClass
获取任意Java类型的字节码文件对象(返回值表示正在运行的那个类或者接口)
-
-
Java中获取一个类的字节码文件的方式:
- getClass方法
- 类名.class
- Class类中有一个静态方法forName(“包名.类名”)
二十三、instanceof
-
应用
对象名 instanceof 对象名 判断前面对象名是否是后面类型的一种实例。
-
代码示例
class Father{ } class Child extends Father{ } public class Main{ public static void main(String[] args){ Child child = new Child(); System.out.println(child instanceof Father); } }
二十四、拓展
- com.dao dao= Data Access Object(数据访问对象) 数据库访问层(持久层)
- com.dao.impl 数据库连接实现
- com.service 业务访问层
- com.service.impl 业务实现
- com.commons/utils 存储通用工具类
- com.controller 前后端交互的代码(前端和;后端的中间层:连接层)
二十五、Lambda 表达式
-
简介
Lambda表达式是Java SE 8中一个重要的新特性。lambda表达式允许你通过表达式来代替功能接口。 lambda表达式就和方法一样,它提供了一个正常的参数列表和一个使用这些参数的主体(body,可以是一个表达式或一个代码块)。 Lambda 表达式(Lambda expression)可以看作是一个匿名函数,基于数学中的λ演算得名,也可称为闭包(Closure)
-
语法
基本语法: (parameters) -> expression 或 (parameters) ->{ statements; }
Lambda表达式由三部分组成:
- paramaters:类似方法中的形参列表,这里的参数是函数式接口里的参数。这里的参数类型可以明确的声明也可不声明而由JVM隐含的推断。另外当只有一个推断类型时可以省略掉圆括号。
- ->:可理解为“被用于”的意思
- 方法体:可以是表达式也可以代码块,是函数式接口里方法的实现。代码块可返回一个值或者什么都不反回,这里的代码块块等同于方法的方法体。如果是表达式,也可以返回一个值或者什么都不反回。
-
函数式接口定义:一个接口有且只有一个抽象方法
-
本质
Lambda表达式本质是一个匿名函数,函数的方法是:返回值 方法名 参数列表 方法体。在,Lambda表达式中我们只需要关心:参数列表 方法体。
二十六、选择排序
-
原理:
数组角标从0开始,将它对应元素依次和后面的元素比较,将小的往前放,第一次比较完毕.最小值就出现在最小索引处!依次这样比较,可以得到一个排好序的数组 -
时间复杂度:O(n^2)
-
空间复杂度:O(n^2)
-
稳定性:不稳定
举例说明:序列58539.我们知道第一遍选择第1个元素“5”会和元素“3”交换,那么原序列中的两个相同元素“5”之间的前后相对顺序就发生了改变。因此,我们说选择排序不是稳定的排序算法,它在计算过程中会破坏稳定性。
-
代码实现
import java.util.Arrays; public class Choice { public static void main(String[] args) { int[] arr = {4,3,2,1}; Choice choice = new Choice(); choice.choice(arr); } //选择排序 public int[] choice(int[] arr){ for (int i = 0; i < arr.length; i++) { for (int j = i+1; j < arr.length ; j++) { if (arr[i]>arr[j]){ int temp = arr[i]; arr[i] = arr[j]; arr[j] = temp; } } System.out.println("第"+(i+1)+"次比较的结果是:"); System.out.println(Arrays.toString(arr)); } return arr; } }
运行效果:
-
和冒泡排序的区别:
-
冒泡排序核心代码
for (int i = 0; i < arr.length-1; i++) { for (int j = 0; j < arr.length-i-1; j++) { if (arr[j]>arr[j+1]){ int temp = arr[j]; arr[j] = arr[j+1]; arr[j+1] = temp; } } }
-
选择排序核心代码
for (int i = 0; i < arr.length; i++) { for (int j = i+1; j < arr.length ; j++) { if (arr[i]>arr[j]){ int temp = arr[i]; arr[i] = arr[j]; arr[j] = temp; } } }
-
比较:冒泡排序是重复地走访要排序的元素列,依次比较两个相邻的元素,而选择排序是依次和后面的元素比较。