java基础
类: 描述事物的抽象体 (包含属性 + 行为)
对象是实例,栈 内存 堆内存--有默认值
基本类型默认0 引用类型是null
方法上的是 形式参数,用于接收实际参数
堆内存的成员变量有默认值
栈内存的局部变量必须定义赋值,不给默认
成员局部,同名就近
new 就是堆里,开内存,建对象,初始化
成员变量和局部变量的区别
在类中的位置不同:成员变量 类中方法外,
局部变量 方法内或者方法声明上;
在内存中的位置不同:
成员变量 堆内存
局部变量 栈内存
生命周期不同:
成员变量 随着对象的存在而存在,随着对象的消失而消失
局部变量 随着方法的调用而存在,随着方法的调用完毕而消失
初始化值不同:
成员变量 有默认的初始化值
局部变量 没有默认的初始化值,必须先定义,赋值,才能使用。
基本类型作为形式参数:形参改变不影响实参
引用类型作为形式参数:影响
方法的形参是引用类型,其实需要的是该类型的对象,只有具体的对象才会调用功能,引用类型给地址值,地址值是new出来的.......java是值传递
因为Java中对基本数据类型(如int、double、char等)进行传递时,实际上传递的是它们的副本,而不是原始变量本身。
对于对象(如类实例),虽然表面上看起来是传递了对象的引用,但实际上传递的是这个引用(即内存地址)的副本,而非对象本身。
这意味着在方法内部对对象状态的修改会影响到原始对象,但如果你试图重新赋值这个引用指向另一个对象,那么原始引用将不会改变。
参数传递机制被称为值传递(pass-by-value),这是 Java 中唯一的参数传递方式。无论传递的参数是基本数据类型还是对象引用,Java 都是通过复制变量的值来进行参数传递的。因此,Java 并不支持引用传递(pass-by-reference)。
值传递意味着当你调用一个方法时,方法参数接收到的是调用时传入的实际值的副本。换句话说,方法内操作的是值的拷贝,而不是原始值本身。因此,任何在方法内对参数进行的修改都不会影响到方法外的原始变量。
在 Java 中,即使传递的是对象,仍然是值传递。这里传递的是对象引用的值,即指向对象的内存地址的值。这意味着方法内对对象的引用本身的修改不会影响原始引用,但通过引用修改对象的内部状态会影响原始对象。
-- 封装--指隐藏对象的属性和实现细节,仅对外提供公共访问方式。将不需要对外提供的内容都隐藏起来。 把属性隐藏,提供公共方法对其访问
对象调用成员变量名是合法的。对象.成员变量------------------------但能乱赋值,赋值之前先判断------逻辑判断再方法种----get() set()---不用set就用.成员变量咋整?? 封装可以强制使用------private 修饰成员变量+方法--- 只本类中访问 私有的
private 大多时候修饰变量,不修饰防范
setName 形参与成员变量同名---->>>就近原则>>自己给自己>>>>>> this 当前类的关键字--解决局部变量隐藏成员变量问题(就近原则导致)--方法被哪个对象调用,this就是谁,因为this在方法里面,谁调用方法
类加载后及案例,方法区,供对象多次调用
构造方法--new 后的就是构造方法, 给对象的数据进行初始化, 给成员变量赋值 (set + 构造)
类组成:成变,构造,成员方法(有参无参有返无返)
XXX s = new XXX()
1加载Student.class文件进内存
2在栈内存为s开辟空间
3在堆内存为学生对象开辟空间
4对学生对象的成员变量进行默认初始化--第一次初始化
5对学生对象的成员变量进行显示初始化--第二次初始化(一般没有)
6通过构造方法对学生对象的成员变量赋值--第三次初始化
7学生对象初始化完毕,
8把对象地址赋值给s变量
类加载方法区,创建对象堆,方法调用即入栈
变量范围定义越小越好,方便回收
static----所有对象共享,一改都变--------静态区,随着类的加载而加载。
this 是对象,随着对象的创建而创建。静态没有this。


main --- 静态方法 可以类名调用,main是虚拟机调用,不用创建对象
静态修饰的是类成员,非静态修饰的是对象成员
代码块 ---- 局部代码块,构造代码块,静态代码块,同步代码块(多线程讲解)。
1局部代码块 在方法中出现;限定变量生命周期,及早释放,提高内存利用率
2构造代码块 在类中方法外出现;多个构造方法方法中相同的代码存放到一起,每次调用构造都执行,并且在构造方法前执行
3静态代码块 在类中方法外出现,加了static修饰 在类中方法外出现,并加上static修饰;用于给类进行初始化,在加载的时候就执行,并且值执行一次。
继承 --使用父类的数据 ,父类一定要先初始化 所以 每一个构造方法的第一条语句默认都是:super() 特点 : 单 + 多层
子类只能继承父类所有非私有的成员(成员方法和成员变量),私有的继承不了;子类调用父类公共方法,父类公共方法可以调用自己的私有变变量,子类直接调用父类私有变变量会报错
其实这也体现了继承的另一个弊端:打破了父类的封装性;
子类不能继承父类的构造方法,但是可以通过super(后面讲)关键字去访问父类构造方法。
不要为了部分功能而去继承
在子类方法中访问一个变量 - 就近原则
首先在子类局部范围找,然后在子类成员范围找,最后在父类成员范围找(肯定不能访问到父类局部范围)
如果还是没有就报错。(不考虑父亲的父亲…)
super的用法和this很像
this代表本类对应的引用。
super代表父类存储空间的标识(可以理解为父类引用)
子类中所有的构造方法默认都会访问父类中空参数的构造方法
为什么呢?
因为子类会继承父类中的数据,可能还会使用父类的数据。所以,子类初始化之前,一定要先完成父类数据的初始化。
每一个构造方法的第一条语句默认都是:super() ,虽然子类中构造默认有super()。但初始化的时候,并不是按照这顺序执行,而是按照分层初始化执行,
成员变量初始化三步走--默认-显示--构造初始化,(基本变量 + 引用变量)
子父类初始化--分层初始化 子类构造的中默认第一行的 super() 仅仅表示要初始化父类数据,再初始化子类数据。
在子类方法中访问一个方法 - 就近原则 --- 方法重写(方法重载)
方法重写-- 方法里调用父类方法功能super.XXX(); 再加上自己业务逻辑 ,组合新方法--方法套方法; 若有static修饰保留传承,总体访问权限不能缩小
继承??? 不想被重写咋整??
final 终结者-final修饰变量的初始化时机,在对象构造完毕前即可
修饰类,类不能被继承
修饰变量,变量就变成了常量,基本类型的值只能被赋值一次, 引用类型的地址值不可变
修饰方法,方法不能被重写
常量: 字面值 (固定值,无名称,不可修改)自定义(通过final关键字声明的有名称的不可变变量 final int a =10;)
运行常量
final int RANDOM = new Random().nextInt();
final String TIME = LocalDateTime.now().toString();
多态 - 不同时刻表现出来的不同状态
有继承或实现关系
方法重写--让多态表现出来的不同状态
有父类或父接口引用指向子类对象
成员变量-无重写
编译看左边,运行看左边
成员方法- 有方法重写-故运行看右边
编译看左边,运行看右边
静态方法(静态和类相关,算不上重写)- 不算重写
编译看左边,运行看左边
所以前面我说静态方法不能算方法的重写
多态的好处 -- 多态利用抽象类和接口,将模块间依赖从具体实现转向抽象,降低耦合度。
提高了代码复用性
提高了程序的维护性(由继承保证) -- 创建新子类继承并实现方法-基于继承关系,只需要维护父类代码,提高了代码的复用性,降低了维护工作的工作量
提高了程序的扩展性(由多态保证) --- 工具类的方法参数,用父类接收--有新add的子类,不用变动
多态的弊端
不能访问子类特有功能--编译不过 解决- 向下转型(强转)
那么我们如何才能访问子类的特有功能呢?
多态中的转型 --- 同一个对象
向上转型 -从子到父 -父类引用指向子类对象 Fu f = new Zi(); 上的成员变量,下的重写方法 -- 成员变量是对象的外在描述(父) 成员方法是对象的功能描述
向下转型 -从父到子 -父类引用转为子类对象 Zi z = (Zi) f; 下的成员变量,下的独有方法
内存--堆有super区

编译时没有对象,只检查语法,运行时才有对象,会匹配-类型转换
.方法套方法,最后运行的是重写的方法
抽象类 - 在Java中,一个没有方法体的方法应该定义为抽象方法,而类中如果有抽象方法,该类必须定义为抽象类。
不给直接 Animal a = new Animal(); (承上,强制避免直接new父类,多态的有力推广)
抽象类不能实例化, 编译报错抽象类不能实例化, 但有构造,构造作用? 用于子类访问父类数据初始化
那么,抽象类如何实例化呢? --- 多态最主要的应用场景,不在具体类而在抽象类
按照多态的方式,由具体的子类实例化。其实这也是多态的一种,抽象类多态。
抽象类的子类 要么是抽象类 要么重写抽象类中的所有抽象方法
抽象类的抽象方法:用于限定子类必须完成某些动作
抽象类的非抽象方法:用于提高代码的复用性
一个类如果没有抽象方法,可不可以定义为抽象类?如果可以,有什么意义? --可,强制使用子类实例化
abstract不能和哪些关键字共存
private 冲突 不能被继承
final 冲突 不能被改
static 无意义 abstract没有方法体 + static直接访问
接口 -- 扩展功能,为了体现事物功能的扩展性,Java中就提供了接口来定义这些额外功能,并不给出具体实现;
和抽象类一样,不调用,不实现。编译不会报错,但若要调用运行不报错,一定要有子类实现
具体类多态 - -抽象类多态 -- 接口多态
接口不是类,是功能的扩展,不能实例化,那么,接口如何实例化呢?
按照多态的方式,由具体的子类实例化。其实这也是多态的一种,接口多态。
接口的子类
要么是抽象类
要么重写接口中的所有抽象方法
成员变量只能是常量 (要求比抽象类更严),可以接口.常量。说明默认静态的。接口有默认修饰符 public static final
构造方法没有,因为接口主要是扩展功能的,而没有具体存在。子类构造里默认第一行的super()是Object
成员方法只能是抽象方法,默认修饰符 public abstract
抽象类 被继承体现的是:”is a”的关系。共性功能
接口 被实现体现的是:”like a”的关系。扩展功能
形式参数是
基本类型
引用类型(类,抽象类,接口)方法入参中, 类不能调用方法,所以要的是该类的对象,抽象类的子类对象,接口的实现类对象
备注:现有形参为抽象类,可编译通过且运行不报错,因为不能用也没调用,一调用就要自己补实现子类。(框架)
返回值类型是
基本类型
引用类型(类(匿名对象),抽象类,接口)
链式编程 : 每次调用完,返回的是一个对象
包

public给所有,private只给本类,protected 只给子类用,,不论子类在哪。 默认只给同一包下不论是谁。

内部类 与外部类没有继承关系。 static可以修饰内部类,在方法位置上
成员内部类: 外部类名.内部类名 对象名 = 外部类对象.内部类对象; 但多 private修饰-数据安全,不给外面用。或static修饰-方便访问 外部类名.内部类名 对象名 = new 外部类.内部类(); -- static修饰可以类直接访问,但又是对象,所以new
Outer.this.num
局部内部类
成员方法里,在局部位置,可以创建内部类对象,通过对象调用内部类方法,来使用局部内部类功能
局部内部类访问局部变量的注意事项:
必须被final修饰? 为什么呢? 成员方法调用完会消失,局部变量也会消失,但局部内部类对象还在堆中没回收。
因为局部变量会随着方法的调用完毕而消失,这个时候,局部对象并没有立马从堆内存中消失,还要使用那个变量。
为了让数据还能继续被使用,就用fianl修饰,这样,在堆内存里面存储的其实是一个常量值。通过反编译工具可以看一下。
匿名内部类- 局部内部类的简化写法 -- 匿名对象
接口 i = new 类名或者接口名() {重写方法;}
本质是一个继承了类或者实现了接口的子类匿名对象
10匿名内部类- lambda 表达式 - 方法引用
16泛型 - 集合+很多对象,向下转型出现转换异常--参考数组--参数化类型
一个泛型,很多应用适配,谁用谁改,我不用改。集合的add方法。
泛型推断
类 接口 谁用谁变,提供者泛型约束
方法--- 泛型不跟类走,那么返回值要 public <T> 返回类型 方法名(T), 任意类型
泛型通配
?不明确可任意类型
?extends E 向下限定 E及其子类
?super E 向上限定 E及其父类
泛型擦除 --反射
可变参数 --形参用无限数组接收
增强for 替代了迭代器(先判断后获取)
19异常

编译期异常处理: 抛,try
调用的方法跟着编译期异常,必须处理,调用的方法跟着运行时异常,可以不管。throw对象, 抛运行期-可以不管 但抛编译期异常-必须处理(否则编译不过)

--编译期间语法检查:成员变量,方法匹配,异常处理,泛型?
运行
23 多线程
24 设计模式
原则-单一,开闭(靠多态),里氏替换(靠多态),依赖注入(依赖抽象类不依实-面向接口抽象类编程),接口分离(多实现),迪米特(低耦合,接口编程)
接口-工厂 简单工厂= 静态工厂 - 新增类,工厂要加if(单厂) 工厂方法,自己做实现抽象工厂类(多厂) 抽象工厂
抽象类-模板
多线程-单例
装饰涉及-IO流
适配器-GUI
26 网络编程
27枚举 反射 新特性
static final 常量选择器--枚举
枚举本质----多例----------常量对象-----常量名就是 new 的对象名, 类 春天= new 类();
继承Enum类(隐藏)---
枚举实现接口 -- 每个常量都要实现-- 匿名内部类
枚举与策略模式
JDK8新特性
函数式接口--接口只有一个抽象方法
注解
标记注解 @Override
可在 编译,类加载,运行时 读取
框架 = 注解 + 反射 + 设计模式
a文档注解
b编译时 有格式检查 (JDK内置3个注解)
c替代配置文件
反射可以获取注解。
自定义注解 必须配上注解的 信息处理流程(反射) 才有意义。
元注解-修饰其他注解的注解

最后加载到内存里,反射读取,XX.class.getAnnotations()



字节码实例

序列化
serialVersionUID什么时候出现?
答:在对象序列化到磁盘时,会根据当前类的结构生成serialVersionUID。
如果serialVersionUID由系统生成,可能导致在类更新后,反序列化失败,无法读取以往的版本。
所以一般情况下,我们会手动在类里面写一个固定的serialVersionUID值。
有什么作用?
答:用于反序列化时比对。反序列化时,先根据当前类的结构生成一个版本ID,和磁盘的版本ID进行比对,一致则反序列化成功,否则反序列化失败。
什么时候需要序列化和反序列化?
答:序列化:当想要把类信息写入磁盘时;反序列化:要从磁盘读取信息时;
Spring的特性IOC、AOP
- IOC:解耦
- AOP:业务增强
浙公网安备 33010602011771号