文章目录
Java SE进阶知识总结-1
面向对象-1-【基础、封装】
基本概念
类和对象的概念
类和对象概念的理解相辅相成:
- 类:是一个模板,描述一类对象的行为(成员方法)和状态(成员属性)、
- 对象:对象是类的一个实例(一个类可以有多个对象,想要创建对象,必须现有类的存在),有相应的行为和状态
类的组成
属性,称为:成员变量
方法,称为:成员方法
成员变量和局部变量的区别
this关键字
- this:代表当前类对象的引用,是一个地址值
- 用途:当局部变量和成员变量出现了重名的情况,java采用就近原则,使用局部变量,通过this关键字,可以让其使用成员变量
public class Account {
private String name;
private double balance;
private String pwd;
//Account类的一个构造器
public Account (String name,double balance,String pwd){
//构造器的实现---初始化对象
this.name = name;
this.balance = balance;
this.pwd = pwd;
}
}
构造方法
什么是构造方法?
- 构建、创造对象的时候,所调用的方法
构造方法的用途?
- 可以用来给对象中的属性进行初始化赋值
构造方法的类别?
- 有两种:无参构造和有参构造
- 无参构造只能有一个;有参构造可以有多个
public class Student {
String name;
int age;
// 无参构造
public Student() {
}
// 带参构造:2个参数
public Student(String name, int age) {
this.name = name;
this.age = age;
}
}
构造方法的特点?
- 方法名与类名一样
- 只有一个权限修饰符和方法名:没有返回值类型(void也没有);没有具体返回值(return也没有)
构造方法的执行时机?
- 创建对象的时候调用,每创建一次,执行一次构造方法
构造方法有哪些特点?
-
不能手动调用构造方法
-
系统默认提供无参构造方法
-
人工定义了有参构造方法,系统就不提供无参构造了,需要自行定义出无参构造
-
构造方法支持重载
封装【对象三要素之一】
什么是封装?
- 使用类设计对象时,将需要处理的数据(成员变量)以及处理这些数据的方法(成员方法),设计到对象中
封装要素
合理隐藏、合理暴露。不要过度封装
权限修饰符
public、protected、private
面向对象-2-【static、final、继承】
static关键字
常规理解一个东西的步骤:是什么?有什么特点?有什么注意事项?有什么用途?
static关键字的用法?
- 静态的意思,可以用于修饰成员变量,也可以修饰成员方法
被static修饰的成员(变量、方法),具有哪些特点?
-
该成员可供该类的所有对象共享
-
多了一种调用该成员的方式:
- 正常调用方式:实例化对象调用(new一个对象)
- 多个调用方式:直接通过类名调用【被static修饰的成员,推荐使用这种方法调用】
-
随着类的加载而加载,优先于对象存在
- 即使没有实例化对象,也可以访问到该成员
若成员方法被static修饰,需要注意如下:
-
方法中只能访问静态成员【包括成员变量和成员方法】:可能当类加载的时候,还没有初始化对象,因此不能访问非静态的成员
-
方法中不允许使用this关键字:当类加载的时候,对象可能还没有创建,因此不能使用this
static关键字的用途?
- 用来修饰成员变量,使得该变量可以成为共享数据的载体,被所有对象调用
- 用来修饰成员方法,常用于工具类,类似System等模块(所有的方法都被static修饰),不需要(也不可以)实例化对象,仅提供方法供访问
final关键字
final关键字的用法?
- 最终的意思,可以用来修饰类、方法、变量
被final修饰的对象的特点?
-
被修饰的类:是最终类,不能被继承
-
被修饰的方法:是最终方法,不能被重写
-
被修饰的变量:
- 是基本数据类型:该变量是常量,不能再被赋值
- 是引用数据类型:地址值不可以变,但其中的内容可以变
被final修饰的变量的命名规范?
- 单个词:纯大写
- 多个词:纯大写且每个词中间用下划线连接
被final修饰的变量的初始化时机?
- 在变量定义的时候
- 在构造方法初始化的时候
继承
什么是继承?
- 继承就是子类拥有父类的特征和行为,具备父类的属性和方法
什么时候使用继承?
- 当类与类之间,存在相同的内容,并且具有 is a的关系【是xxx的一个xxx】,就可以考虑使用继承
为什么要使用继承?
- 提高代码的重用性
- 优化代码,修改方便
- 类与类之间产生关系,是多态的前提
Java中怎么实现继承?
- 通过extend关键字来实现
Java中继承的特点?
-
Java只支持单继承,不支持多继承,但支持多层继承
-
继承关系中的成员变量:
- 子类和父类中出现重名的变量,就近原则,子类优先使用自己的变量。若要用父类变量:super.变量名
- 该用法同this一样:this指向该类地址;super指向父类地址
-
继承关系中的成员方法:
- 在子类中运行父类的方法:
super.method()
- 在子类中重写父类的方法:(1)保证方法声明一致:方法名、参数、返回值类型均一致;(2)若要判断是否是重写,可以用@override装饰器装饰一下
- 在子类中运行父类的方法:
-
继承关系中的构造方法:
- 子类的构造过程中必须调用基类的构造方法
- 若显式调用基类的构造方法,必须放在子类构造方法的第一行
- 若无显式调用基类的构造方法,则默认调用基类的空参构造方法(基类无空参构造方法会报错)
继承关系中的内存关系?
- 图解
- 子类在初始化的时候,会在其内存空间留一块存储父类数据的内存
- 该块内存可以被继承到,但是会根据权限修饰符的不同,有时不具备对其的访问条件【一定能继承到,不一定能访问到】
this和super的区别?
面向对象-3-【包、抽象类、接口、多态】
包
什么是包?
- package,本质就是文件夹,管理Java类的文件夹
怎么建包?
package 公司域名倒写.技术名称 // 全部小写,且具有意义。package后面所有的内容都是包名
// 建包语句必须在文件第一行写出【IDEA工具默认会给出建包语句】
怎么导包?
- 相同包下的类可直接访问,不同包之间的类访问才需要导包:
import 包名.类名
- 假如一个包中的两个类,他们名字一样,还都被另一个类用到了。
- 此时,只能通过导包的方式导入一个类,导入后可仅通过类名访问
- 另一个类需要带包名访问,不能只通过写类名访问
抽象类
什么是抽象类?
- 抽象类是特殊的父类,内部写有抽象方法
- 抽象方法:将共性的行为抽象到父类中,发现其实现逻辑无法明确给出,就只定义方法,具体逻辑,由继承抽象类的子类实现
- 如果一个类中有抽象方法,该类就必须声明为抽象类
抽象类的定义格式?
// 抽象类
public abstract class 类名{};
// 抽象方法
public abstract 返回值类型 方法名(参数列表);
抽象类有什么注意事项?
- 自身:不能实例化;存在构造方法,可供子类访问;类中可以编写普通方法
- 对于继承抽象类的子类:要么重写所有抽象方法,成为普通类;要么依旧是抽象类
接口
接口相关概念
什么是接口?
- 是一个抽象类型,是抽象方法的集合,体现的思想是对规则的声明
- 在Java中,接口体现为对行为(方法)的抽象
接口命名规范?
public interface 接口名{}
接口有什么特点?
- 自身:不能被实例化,且内部全是抽象方法
- 继承接口的子类:要么重写所有抽象方法,成为普通类;要么重写部分抽象方法,成为抽象类
接口的内部成员有什么特点?
- 成员变量:只能是常量【默认提供修饰符:
public static final
】 - 构造方法:没有构造方法【继承接口的实现类里面的构造方法,访问的是objects类的父类构造方法,而不是接口的构造方法】
- 成员方法:只能是抽象方法【默认提供修饰符:
public abstract
】
普通类和接口间的相互关系
类和类之间?
- 继承关系,仅单继承和多层继承,不可多继承
类和接口之间?
- 实现关系:可以单实现、可以多实现、可以在继承的同时多实现
// 单实现
public class 类名 implements A {}
// 多实现
public class 类名 implements A, B {}
// 继承中多实现
class Zi extends Fu implements A, B {}
接口和接口之间?
- 继承关系,可以单继承,也可以多继承
- 可以多继承的原因是:接口中全是抽象方法,就算不同的父类中有一样的方法名,继承哪一个也都无所谓
- 类不能多继承的原因是:父类中若有相同的方法,不知道该继承哪一个(python中是就近原则,所以python支持多继承)
抽象类和接口间的相互关系
两者成员变量间的区别?
- 抽象类:可以定义常量,可以定义变量
- 接口:只能定义常量
两者成员方法间的区别?
- 抽象类:可以定义具体方法,也可以定义抽象方法
- 接口:只能定义抽象方法
两者构造方法的区别?
- 抽象类:有构造方法
- 接口:没有构造方法
接口新特性-Java8
Java8中新的接口特性?
- 允许在接口中定义默认方法和静态方法
默认方法和静态方法的定义格式?
public interface MyInterface {
// 默认方法的定义格式
public default void myMethod() {}
// 静态方法的定义格式
public static void myStaticMethod() {}
}
新特性的应用场景?
- 默认方法(可被重写):
- 解决接口升级的问题。以往都是抽象方法,接口引入新的抽象方法后,所有的实现类中都要重写新的方法,影响范围极大
- 有了默认方法后,已经实现该接口的实现类,不需要再改动代码;新的实现类,可以重写新增的默认方法
- 静态方法(不可被重写):
- 解决接口升级的问题。常规,同上
- 可以在不重写且不增加实现类的基础上,直接
接口.方法
的调用形式,提供新的功能
新特性的注意事项?
- 默认方法不是抽象方法,不强制重写【可以重写,重写之后记得去掉
default
关键字即可】 - 默认方法中的
public
关键字可以省略,default
关键字不可以省略 - 如果实现了多个接口,且接口中有相同的方法声明,子类就必须对该方法进行重写【强制】
接口新特性-Java9
Java9中的接口新特性?
- 允许定义私有(静态)方法
私有(静态)方法的定义格式?
public interface MyInterface {
// 私有方法的定义格式
public private void myMethod() {}
// 静态私有方法的定义格式
public private static void myStaticMethod() {}
}
私有(静态)方法的定义格式?
- 静态方法逻辑已经写完了,即不可重写
- 私有静态方法只能在接口内部调用
多态
什么是多态?
同一个行为具有多个不同表现形式或形态的能力,称为多态
多态的实现前提?
1、有继承或实现
2、有方法重写
abstract class Animal {
public abstract void eat();
}
// 有继承
class Dog extends Animal {
// 有方法重写
@Override
public void eat() {
System.out.println("狗吃肉");
}
}
class Cat extends Animal {
@Override
public void eat() {
System.out.println("猫吃鱼");
}
}
3、有父类引用(等号左边)指向子类对象(等号右边)
package com.itheima.polymorphism;
public class PolymorphismTest1 {
public static void main(String[] args) {
// 有父类引用指向子类对象
Animal a = new Dog();
useAnimal(a);
useAnimal(new Cat());
}
public static void useAnimal(Animal a) { // Animal a = new Dog();
a.eat(); // Animal a = new Cat();
}
}
【补充】子类引用指向子类对象:Dog a = new Dog();
**多态的效果就是:**同一个表现吃的代码,输入对象不同,吃的结果也不同
多态的成员访问特点
非静态成员
- 访问成员变量:编译看左边(看父类是否有该成员),执行看左边(执行父类的成员变量)
- 访问成员方法:编译看左边(看父类是否有该方法),执行看右边(执行子类的成员方法,不执行父类的方法,防止该方法是一个抽象方法)
静态成员
- 推荐使用
类名.成员
调用。即使使用对象实例调用这种方法,在.class
编译的时候也会变为类名调用 - 不管是成员变量或成员方法,都是调用的左边的【父类的】(静态的成员方法,不用担心是抽象方法的问题,都是调用左边的)
体现成员访问特点的示例
class Fu {
int num = 10;
public void show() {
System.out.println("Fu...show");
}
public static void print(){
System.out.println("Fu...print");
}
}
class Zi extends Fu {
int num = 20;
@Override
public void show() {
System.out.println("Zi...show");
}
public static void print(){
System.out.println("Zi...print");
}
}
package com.itheima.polymorphism;
public class PolymorphismTest2 {
public static void main(String[] args) {
// 多态
Fu f = new Zi();
// 结果:10
// 访问成员变量,编译输出均看左边,输出父类中的值
System.out.println(f.num);
// 结果:Zi...show
// 访问非静态成员方法,编译看左边:字节码文件中是zi.show();执行看右边:输出结果是子类中的值
f.show();
// 结果:Fu...print
// 访问静态成员方法,编译看左边:字节码文件中是Fu.print();执行看右边:输出结果是父类中的值
f.print();
}
}
多态的好处与不足?
好处:提高程序的扩展性
- 对象多态:将方法的形参定义为父类类型,这个方法可以接受该父类的任意子类类型
- 行为多态:同一个行为具有多个不同表现形式或形态
不足
- 不能使用子类的特有成员:因为编译都是看左边,子类的特有成员,父类不具备,编译就不通过
多态中的转型问题
向上转型【父类引用指向子类对象】
FU f = new Zi();
向下转型【子类引用指向父类对象】
Zi z = (Zi)f;
示例
package com.itheima.order;
import java.util.Scanner;
public class Test {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("请输入: 1. 国内订单 2. 国外订单");
OrderService orderService = null;
int choice = sc.nextInt();
switch (choice) {
case 1:
// 创建国内订单的业务类
orderService = new OrderServiceImpl(); // 向上转型
break;
case 2:
// 创建国外订单的业务类
orderService = new OverseasServiceImpl(); // 向上转型
break;
}
// instanceof : 判断左边的引用, 是否是右边的数据类型
if(orderService instanceof OverseasServiceImpl){
OverseasServiceImpl osi = (OverseasServiceImpl) orderService; // 向下转型
osi.check(); // OverseasServiceImpl子类对象特有的方法
}
orderService.create();
orderService.findOne();
orderService.findList();
orderService.cancel();
orderService.finish();
orderService.paid();
}
}
instanceof关键字
-
用途:判断一个对象是不是一个类的实例
-
用法:
实例对象 instanceof 类名
面向对象其他知识-4-【代码块、内部类、Lambda表达式】
代码块
局部代码块
定义位置:方法中定义
作用:可以限定生命周期,提早释放(现在电脑内存普遍比较大,不怎么用这个)
public class BlockTest {
public static void main(String[] args) {
// 内部代码块
{
int num = 10;
System.out.println(num);
}
xxx;
xxx;
}
}
构造代码块
位置:在类中的方法外定义
特点:每次构造方法执行,该代码块就会在构造方法执行前进行执行
好处:提高构造方法中代码的复用性
class Student {
{
System.out.println("Student类的构造代码块");
System.out.println("好好学习");
}
public Student(){
System.out.println("空参构造方法...");
}
public Student(int num){
System.out.println("带参构造方法...");
}
}
静态代码块
位置:类中的方法外定义
特点:需要static关键字修饰,随着类的加载而加载,只执行一次
好处:在类加载的时候做一些数据初始化的操作
class Student {
// 静态代码块
static {
System.out.println("静态代码块");
}
// 构造代码块
{
System.out.println("构造代码块");
}
public Student(){
System.out.println("空参构造方法...");
}
public Student(int num){
System.out.println("带参构造方法...");
}
}
静态代码块和构造代码块所处的位置是一样的,都是在类中的方法外,区别在于一个有static修饰,另一个没有
同步代码块
后续再说
内部类
定义在类里面的类
成员内部类
**创建位置:**定义在类中方法外的一个类
成员内部类定义示例及成员访问
class MyOuter {
int num = 10;
class MyInner {
int num = 20;
public void show(){
int num = 30;
System.out.println(num); // 30
System.out.println(this.num); // 20
System.out.println(MyOuter.this.num); // 10
}
}
}
成员内部类的实例化对象创建格式
外部类名.内部类名 对象名 = new 外部类对象().new 内部类对象();
Outer.Inner in = new Outer().new Inner();
成员访问特点
- 内部类访问外部类成员:直接访问,包括私有(创建内部类的时候,外部类一定有创建)
- 外部类访问内部类成员:需要创建对象访问(创建外部类的时候,内部类不一定有创建)
class Outer {
private void method(){
System.out.println("method...");
Inner i = new Inner();
// 外部类访问内部类成员
System.out.println(i.num);
}
class Inner {
int num = 10;
public void show(){
System.out.println("show...");
// 内部类访问外部类成员
method();
}
}
}
静态内部类
**创建位置:**定义在类中方法外的一个类(静态内部类就是static修饰的成员内部类)
静态内部类的实例化对象创建格式
外部类名.内部类名 对象名 = new 外部类名.内部类对象();
Outer.Inner in = new Outer.Inner(); // 这里Outer后面没有括号
成员访问特点
-
内部类访问外部类成员:
- 外部类的静态成员变量,可以直接访问
- 外部类的非静态成员变量,需要创建外部类对象后再访问(类加载的时候,静态内部类就创建了,此时外部类还没创建,因此要访问,需要先创建对象)
-
外部类访问内部类成员:需要创建对象访问?【暂时存疑】
class OuterClass {
int num1 = 10;
static int num2 = 20;
static class InnerClass {
public static void show(){
System.out.println("show...");
OuterClass o = new OuterClass();
System.out.println(o.num1);
System.out.println(num2);
}
}
}
局部内部类
**局部内部类的创建位置:**方法、代码块、构造器等执行体中
class A {
public void show(){
class B {
public void method(){
System.out.println("method...");
}
}
B b = new B();
b.method();
}
}
局部内部类的成员访问特点?
- 只能在方法内、代码块、构造器内部访问
- 访问前需要先创建对象,再访问
匿名内部类
什么是匿名内部类? 匿名内部类本质是一个特殊的局部内部类(定义在方法内部)
**匿名内部类的前提:**需要存在一个接口或类,才能写匿名内部类
**匿名内部类的特点:**可以使代码简洁,在定义一个类的同时对其进行实例化
定义格式
new 类名\接口名 () {
}
// new 类名(){} : 代表继承这个类
// new 接口名(){} : 代表实现这个接口(需要重写里面所有的抽象方法)
示例
- 有一个接口
interface Inter {
void show();
}
class InterImpl implements Inter {
@Override
public void show() {
System.out.println("InterImpl...show...");
}
}
- 匿名内部类
public class AnonClassTest1 {
public static void main(String[] args) {
// 问题: 方法的形参是接口类型, 我们该传入的是什么?
// 答案: 传入的是该接口的实现类对象
// 不适用匿名内部类:需要借助接口实现来完成
// 暗含着:父类引用指向子类对象
useInter(new InterImpl());
// 使用匿名内部类:不需要额外写接口的实现,直接定义匿名内部类,即可完成功能
useInter(new Inter(){
@Override
public void show() {
System.out.println("匿名内部类...show...");
}
});
}
public static void useInter(Inter i){
i.show();
}
}
Lambda表达式
简化匿名内部类的写法
正常写匿名内部类,鼠标移动到匿名内部类()里面,alt+enter,一键修改为lambda表达式
Lambda表达式和匿名内部类的区别
使用限制不同
- 匿名内部类 : 可以操作类、接口
- Lambda表达式 : 只能操作函数式接口(只有一个方法的接口、类)
实现原理不同
- 匿名内部类:编译之后,产生一个单独的.class字节码文件
- Lambda表达式:编译之后,没有一个单独的.class字节码文件
函数式接口、匿名内部类的区别、Lambda表达式
- 函数式接口是指只有一个方法(函数)的接口
- 匿名内部类可以简化接口的写法
- 当匿名内部类的接口是函数式接口,可以写为lambda表达式