------------恢复内容开始------------
# java高级应用1.补充
当方法中不存在与对象相关的方法时 比如 直接的数字计算 输出 等 都可以写成静态方法 集合成一个工具类
1.类变量与类方法(静态变量 / 静态方法)
也就是记录变量和方法的使用次数 , 每次随着类的生成而生成 随着类的消失而消失?
static 和 final ? 静态变量 (打点计时器) final 定义常量.
类变量 又叫静态属性, 是该类所有的对象共享的变量,任何一个该类的对象请访问它时,取出来的值都是一样的,同样 任何变量去修改时,也是修改的同一个值.
特点:-
根据版本的不同
- static 在java7以前 在方法区的静态域中
- static 在java7及以后在堆中 随着类的生成 生成一个class对象,
内存区域:
- 不管static在哪里 静态变量在同类中所有对象共享
- 在类加载的时候就生成了.
<img alt="1667387183328" loading="lazy">
语法:
访问修饰符 static 数据类型 变量名:[推荐]
static 访问修饰符 数据类型 变量名:
访问方式:
类名.类变量名 [推荐]
对象名.类变量名
注意: 访问修饰符无异
类变量细节问题
1.使用时, 匿名对象也可以 , 用于统计同一变量时
2.类变量该类全部对象共享, 实例变量是对象独享
3.必须加上static. 别称:如下
4.访问方式, 类名.类变量名, 对象名.类变量名
<img alt="1667386757410" loading="lazy">
5.实例变量不能类名.类变量名访问.
6.类加载时就初始化了.
7,其生命周期随类的加载开始而生成, 随类的消亡而销毁.
<img alt="1667387082507" loading="lazy">- package static_;
- /**
- * @Auther: qianl
- * @Date: 2022/11/2 18:42
- * @Description:
- */
- public class VisitStatic {
- public static void main(String[] args) {
- //类名.类变量名
- //随着类的加载而创建,即使没有实例化也可以访问.
- System.out.println(Student.fee);
- //0.0
- //匿名对象,记录在构造器中 一样有用.
- new Student("1",13);
- new Student("2",13);
- new Student("3",13);
- System.out.println(Student.fee);
- //39.0
- }
- }
- class Student{
- private String name;
- public static double fee;
- public Student(String name, double fee) {
- this.name = name;
- this.fee += fee;
- }
- }
复制代码 类方法问题:
使用情况:
当需要不创建实例, 也可以调用方法(当工具类使用)
或者一些通用的方法 ,就可以直接设计成静态方法,注意就不用创建对象就能使用了. 比如 打印数组,冒泡排序等.
创建自己的工具类时.
这时将方法写成静态方法.
1,方法修饰static 变成静态方法
2.静态方法就可以访问静态属性/变量
3.不能使用this引用
4.对象可以使用 但idea里无法"点出"- package static_;
- /**
- * @Auther: qianl
- * @Date: 2022/11/2 18:42
- * @Description:
- */
- public class VisitStatic {
- public static void main(String[] args) {
-
- Student.payFee(100);
- Student.getFee();
- Student student = new Student("2", 100);
- student.payFee(100);
- student.getFee();
- }
- }
- class Student{
- private String name;
- private static double fee;
- public Student(String name, double fee) {
- this.name = name;
- this.fee += fee;
- }
- //1,方法修饰static 变成静态方法
- //2.静态方法就可以访问静态属性/变量
- public static void payFee(double fee){
- //this.fee += fee; 静态变量不能使用this引出.
- Student.fee += fee;
- }
- public static void getFee(){
- System.out.println(Student.fee);
- }
- }
复制代码 总结细节
1.类方法和普通方法 都是随着类的架子啊而加载的, 将结构信息存储在方法区.
2.类方法中无法使用this参数.普通方法中隐含this参数
3.类方法可以通过类名调用,也能通过对象名调用.
4.普通方法 和对象有关.需要通过对象名调用, 比如对象名.方法名(参数).不能通过类名调用.
5.类方法不能使用 this 和 super 关键字 静态方法 只能访问静态的方法和静态的变量.
(静态方法只能访问静态成员)
6.普通成员方法 可以访问 非静态成员 ,也能访问 静态成员
练习:
输出结果:
1.运行类中的静态方法 : 输出 count = 9 (后++ 类中 count = 10)
2.再次运行静态方法 输出 count = 10 (后++ 类中 count = 11)
3.打印此时的count值 为11
<img alt="1667400604229" loading="lazy">
1: 看有没有错误 , 修改 并输出
问题1 getTotalPerson方法中 使用了非静态属性 id
修改id为静态..
然后 id+1 =1; 输出 total =0;
生成一个对象,
走构造器 total = 0 total+1;
id = 1;
再输出 id = 1+1;
total =1; 输出 1
0 1
<img alt="1667401764237" loading="lazy">
第三题:
1: 看有没有错误 , 修改 并输出total
问题1 静态方法内 不能使用this. 注销.
第一句: total = 3;
第二句: total = 3+1
id = total; id =4 total=4
<img alt="1667402621089" loading="lazy">
练习小结:
- 静态方法只能访问静态成员,
- 非静态方法,可以访问所有成员
- 编写代码时,依然遵循访问权限规则
2.main方法 static(静态)
main方法语言
- main方法是虚拟机调用的
- java虚拟机调用类的main()方法 必须是public
- java在运行main()方法时 不必创建对象,所以必须是static
- 该方法接受String类型的数组参数, 数组中保存了执行java命令时给所允许的类的参数.(类的参数)
- java执行的程序 参数1 参数2 参数3
<img alt="1667404103533" loading="lazy">
- main() 方法具有一个字符串数组参数,用来接收执行 Java 程序的命令行参数。命令行参数作为字符串,按照顺序依次对应字符串数组中的元素。
- 一个类只能有一个main方法.
//main方法 可以接受一个字符串数组 但是没有返回值
public static void mian(String[] args){
}- D:\myJava>java TestMain apple banana
- 一共有 2 个参数
- apple
- banana
复制代码 main() 方法可以以字符串的形式接收命令行参数,然后在方法体内进行处理。
IDEA传入main方法 String参
<img alt="1667413546667" loading="lazy">
<img alt="1667413620106" loading="lazy">
和普通类的区别:
1.可以直接调用main所在类的静态方法或静态属性.(相同)
2.不能直接访问非静态 (相同 ) 必须创建一个实例对象后, 才能去访问类中的非静态方法(相同) 其他类里的静态方法也可以.
3.代码块
代码化块 又称初始化块 属于类中的成员 [类的一部分 ]
类似于方法, 将逻辑语句封装在方法体内 使用{} 包围
和方法不同, 没有方法名, 没有返回值 没有参数 只有方法体. 不能通过显性调用, 只能在加载类时, 和创建对象时 隐形调用.
基本结构:1.修饰符 就是默认 作用范围: 本类 本包
2.能写修饰符 只能写static 称为静态代码块
3.逻辑语句无要求,可以是任何逻辑语句(输入/输出/方法调用/循环/判断)
代码块
1.相当于另一种形式的 构造器, (对构造器的补充) 可以做初始化的操作.
2.如果多个构造器中重复的语句,就可以抽取到初始化代码块中,提高代码重用性.- package static_;
- /**
- * @Auther: qianl
- * @Date: 2022/11/3 02:49
- * @Description:
- */
- public class CodeBlock01 {
- public static void main(String[] args) {
- Movie movie = new Movie();
- //名字hhn
- }
- }
- class Movie{
- private String name;
- {
- name = "hhn";
- System.out.println("名字"+name);
- }
- }
复制代码 代码块细节:
理解: 普通代码块是构造器的补充
静态代码块 是类的初始化的补充
- 代码块语句 在生成对象的时候 随着 类的加载而执行.并且没创建一个对象就执行一次
- 随着类的加载 静态代码块 只会执行一次.
- 类加载的情况
- 创建对象实例 new
- 创建在子类对象实例,父类被加载时
- 使用类的静态成员时(静态属性和静态方法.)
- 普通代码块,创建对象实例,会被隐形的调用. 被创建一次就会被调用一次.
- 普通代码块 如果只是使用类的静态成员时, 不会执行.
1.使用静态成员 时 会调用静态代码块 不会使用普通代码块
2.new / 子类加载父类 都会调用普通代码块(一个对象一次). 静态代码块(一次)
静态代码块从类生成以后 只会被调用一次 后续多少个对象 静态方法的引用都不会在调用,
也就是 静态代码块 默认 public static int count = 1; 只有一次共用使用机会- package static_;
- /**
- * @Auther: qianl
- * @Date: 2022/11/3 02:49
- * @Description:
- */
- public class CodeBlock01 {
- public static void main(String[] args) {
- Movie movie01 = new Movie();
- Movie movie02 = new Movie();
- //名字hhn
- System.out.println(Movie.i);
- System.out.println(movie01.i);
- Movie.love();
- movie02.love();
- /*我是静态代码块
- 我是普通代码块
- 我是普通代码块
- 0
- 0
- 静态方法
- 静态方法*/
- }
- }
- class Movie{
- private String name;
- public static int i=0;
- static{
- System.out.println("我是静态代码块");
- }
- {
- name = "hhn";
- System.out.println("我是普通代码块");
- }
- public Movie(){
- }
- public Movie(String name) {
- this.name = name;
- }
- public static void love(){
- System.out.println("静态方法");
- }
- }
复制代码 执行顺序:
static优先级比普通成员 优先级高
同static成员(属性,代码块,方法) 按顺序来
例子: 优先加载属性, 任何是静态代码块. (按顺序)
<img alt="1667418210753" loading="lazy">
static比普通高一级
加入普通代码块和普通属性.
同普通成员 优先级一致 按 "顺序"**执行
在static代码块 后被执行.
<img alt="1667418557209" loading="lazy">
加入构造器
构造器最后才被使用
在所有代码块后执行.
<img alt="1667422860992" loading="lazy">
代码块的最前面 隐含了 super() 和调用普通代码块.
第一: super必须在第一行. 调用父类!
然后调用普通代码块
输出顺序:
先加载父类 与子类的静态成员(顺序)
父类代码块
父类构造器
子类代码块
子类构造器
<img alt="1667423022927" loading="lazy">
注意!!!!
静态代码块和静态属性总是被优先执行的!
比父类的普通代码块都优先.
<img alt="1667423630553" loading="lazy">- package static_;
- /**
- * @Auther: qianl
- * @Date: 2022/11/3 13:05
- * @Description:
- */
- public class CodeBlockDetail {
- //测试代码块 构造器 初始属性 在子类与父类的调用顺序
- public static void main(String[] args) {
- //先分析一波
- //优先级, 静态比非静态高 同优先级按顺序进行.
- B b = new B();
- //1.新建该类 先加载B()类信息 然后发现继承A() 加载A()类信息
- //2.加载A()中的静态属性 静态代码块(顺序进行)
- //3.加载B()中的静态属性 静态代码块 理由: 类的静态成员随着类生成而生成
- //开始走构造器 super();
- //4.然后加载父类普通代码块
- //5.加载父类构造器 理由: 先进行了父类的初始化(代码块是构造器的补充)
- // 代码块随着构造器而产生 先代码块 后构造器
- //6.super()结束 开始子类构造器 子类代码块
- //7.子类构造器
- /*这是父类静态属性
- 这是父类的静态代码块
- 这是子类静态属性
- 这是子类的静态代码块
- 这是父类普通属性
- 这是父类的普通代码块
- 这是父类的空构造器
- 这是子类普通属性
- 这是子类的普通代码块
- 这是子类的空构造器
- */
- }
- }
- class A{
- public static int aStaticInt=aShowStatic();
- public int aInt=aShow();
- static {
- System.out.println("这是父类的静态代码块");
- }
- {
- System.out.println("这是父类的普通代码块");
- }
- public A() {
- System.out.println("这是父类的空构造器");
- }
- public static int aShowStatic(){
- System.out.println("这是父类静态属性");
- return 100;
- }
- public static int aShow(){
- System.out.println("这是父类普通属性");
- return 100;
- }
- }
- class B extends A{
- public static int bStaticInt=bShowStatic();
- public int bInt=bShow();
- static {
- System.out.println("这是子类的静态代码块");
- }
- {
- System.out.println("这是子类的普通代码块");
- }
- public B() {
- System.out.println("这是子类的空构造器");
- }
- public static int bShowStatic(){
- System.out.println("这是子类静态属性");
- return 100;
- }
- public static int bShow(){
- System.out.println("这是子类普通属性");
- return 100;
- }
- }
复制代码 注意:
静态代码块只能调用静态成员. 普通代码块可以调用任意成员 静态代码块类似于静态方法.
练习:
以下代码输出什么:
主方法 调用了静态属性
加载类 加载静态成员 然后同时触发了静态代码块 输出: in static block!;
第一句话 时 total = 100;
第二句话 时 total = 100;
<img alt="1667473187503" loading="lazy">
第二题:
看输出什么
主方法: 创建了Test() 的无参构造器;
第一步 Test静态资源: 输出: 静态成员sam初始化;
Test静态资源: 静态代码块 输出: static块执行;
第二步: 加载普通代码块 和普通属性的初始化 所以 sam1 初始化 输出:
sam1成语初始化
第二步: 加载Test构造器: Test默认构造器被调用.
<img alt="1667473546075" loading="lazy">
4.单例(单个实例)设计模式
1.静态方法和静态属性的经典使用
2.设计模式是在大量实践中总结和理论化之后选优的代码结构\编程风格\以及结局问题的思考方式
经典棋谱\ 不同的棋局\使用对应的不同棋盘 而且有时候还会使用多种棋盘解决同一种事情.
重点: 对某个类只能存在一个对象实例, 并且该类只提供一个取得其对象实例的方法 对某个类操作
<img alt="1667494790794" loading="lazy">
饿汉式: 实例在类加载时就被创建。
1)构造器初始化 (防止直接new对象)
2)类的内部创建对象
3)向外暴露一个静态的公共方法. getlnstance
4)代码实现- package static_;
- /**
- * @Auther: qianl
- * @Date: 2022/11/4 02:56
- * @Description:
- */
- public class SingleTonTest {
- public static void main(String[] args) {
- /* SingleTon01 s = SingleTon01.getInstance();
- System.out.println(s);
- SingleTon01 s1 = SingleTon01.getInstance();
- System.out.println(s1);
- System.out.println(s == s1);// == 引用类型 比较地址
- //true
- */
- //称为饿汉式的原因是 在类加载的时候 该对象作为静态资源也被加载了
- //所以该对象无论是否被使用就先创建了再说
- System.out.println(SingleTon01.i);
- //先是类加载了 所以构造器也被使用了
- //然后输出100
- }
- }
- class SingleTon01 {
- private String name;
- public static int i =100;
- private static SingleTon01 singleTon01
- = new SingleTon01("小红");
- private SingleTon01(String name) {
- System.out.println("构造器被调用了");
- this.name = name;
- }
- //返回类型是本类 方法名 获取实例
- public static SingleTon01 getInstance() {
- return singleTon01;
- }
- @Override
- public String toString() {
- return "SingleTon01{" +
- "name='" + name + '\'' +
- '}';
- }
- }
复制代码 懒汉式:当类加载时 实例没有被创建,
- package static_;
- /**
- * @Auther: qianl
- * @Date: 2022/11/4 03:13
- * @Description:
- */
- public class SingleTon02 {
- public static void main(String[] args) {
- System.out.println(Cat.i);
- //999
- System.out.println(Cat.getInstance());
- //构造器被调用 然后输出哈希值
- /*999
- 构造器被调用了
- static_.Cat@6d6f6e28*/
- }
- }
- class Cat{
- private String name;
- public static int i=999;
- private static Cat cat;
- private Cat(String name) {
- System.out.println("构造器被调用了");
- this.name = name;
- }
- //当被使用到时 才会生成对象
- public static Cat getInstance(){
- if(cat ==null){
- cat = new Cat("小可爱");
- }
- return cat;
- }
- }
复制代码 饿汉式与懒汉式的异同:
相同点:
1,都是单例设计模式的实现
2.都是实例在编译过程中写死 而不被人创建
3.都只有一个public 的 getInstance()方法 获取实例(不是创建)
不同点:
1.饿汉式是类加载过程中 就直接创建了实例,而懒汉式 在调用getInstance()方法时才被创建实例
2.饿汉式存在资源浪费的可能 (类加载就创建了实例,只调用其静态属性时 就会浪费资源)
3.饿汉式不存在线程安全问题(类加载就生成实例 ) 而懒汉式存在线程安全问题( 运行时加载, 可能被其他调用该实例的线程抢先)
4.java.lang.Runtime 就说经典的单例模式
单例模式有八种方式.
Runtime源码:
这就是一个饿汉式 的单例实现方式
直接在静态属性(类属性)创建了随着类加载而生成的对象.
提供一个getRuntime()方法获取实例
其构造器是私有的.- public class Runtime {
- private static Runtime currentRuntime = new Runtime();
- /**
- * Returns the runtime object associated with the current Java application.
- * Most of the methods of class Runtime are instance
- * methods and must be invoked with respect to the current runtime object.
- *
- * @return the Runtime object associated with the current
- * Java application.
- */
- public static Runtime getRuntime() {
- return currentRuntime;
- }
- /** Don't let anyone else instantiate this class */
- private Runtime() {}
复制代码 5.final (最终的) 又叫常量 关键字
可以修饰类\属性\方法\局部变量
使用场景:
- 类不想被继承的时候, 使用final进行修饰
- 父类某方法不想被在子类覆盖重写(override)时,使用final进行方法修饰
- 当不希望某属性被修改时 使用final进行修饰 例如 派(Π) 根号2等常量的取值范围.
- 当不希望某个局部变量被修改, 可以使用final修饰 比如 计算工资时 某比例
命名格式:
全部大写 单词间使用_链接- private static final double THE_PI=3.14; // Π的设置在3.14
复制代码 细节1:
- 又称常量 命名必须 XX_XX_XX
- 修饰属性时 定义时必须赋初值, 并且不能再修改. 赋值可以在如下任何位置
- 如果final修饰的属性是静态的,初始化的位置只能是:
- final类不能继承,但是可以实例化对象
- 如果类不是final类 但有final方法 则该类不能重写 但能继承.
- package final_;
- /**
- * @Auther: qianl
- * @Date: 2022/11/4 11:53
- * @Description:
- */
- public class FinalDetail {
- }
- class AA {
- //定义时赋值
- public final double TAX_RATE = 0.8;
- public final double TAX_RATE2;
- public final double TAX_RATE3;
- //构造器赋值
- public AA() {
- TAX_RATE3 = 1.1;
- // TAX_RATE6 = 100;
- }
- //代码块赋值
- {
- TAX_RATE2 = 8.8;
- }
- //静态常量 定义时赋值
- public static final double TAX_RATE4 = 100;
- public static final double TAX_RATE5;
- // public static final double TAX_RATE6;
- //在静态代码块赋值
- static {
- TAX_RATE5=1000;
- }
- }
复制代码 final方法的继承 可以继承使用但不能重写- public class FinalDetail {
- public static void main(String[] args) {
- bb a1 = new bb();
- a1.test();
- //test
- }
- }
- class aa{
- public final void test(){
- System.out.println("test");
- }
- }
- class bb extends aa{
- }
复制代码 细节2:
- final类的话 本类中不能将方法修饰写成final方法
- final不能修饰构造器
- final和static往往搭配使用, 效率更高 , 不会导致类加载 ,底层编译器进行了优化 节省了加载静态代码块的工作,也不会使得类进行加载. 测试在第二顺序时
- public class FinalDetail {
- public static void main(String[] args) {
- System.out.println(Demo.i);
- //直接输出16 而不会加载静态代码块
- //甚至不会生成比 i 应该更早生成的i1 这个静态常量
- //所以 应该是 静态加常量的值 会被直接写入方法区的常量池 可以直接用类名进行调用
- //而不会进行类的加载
- }
- }
- class Demo{
- public static final int i1 = test();
- public static final int i = 16;
- static{
- System.out.println("静态构造器被触发了");
- }
- public static int test(){
- System.out.println("这是第一个静态常量");
- return 0;
- }
- }
复制代码 - 包装类的(Integer,Double,Float,Boolean 等都是final) String也是final类.
因为是final类型 所以不能被继承 不能自己改写
课程练习:
1.计算圆面积 Circle- public class Circle {
- public static void main(String[] args) {
- Circle01 circle01 = new Circle01(200);
- System.out.println(circle01.MathCircle());
- }
- }
- class Circle01{
- //半径
- private double radius;
- private final double PI = 3.14;
- public Circle01(double radius) {
- this.radius = radius;
- }
- public double MathCircle(){
- return PI*radius*radius;
- }
- }
复制代码 2.阅读程序:
final int X 定义属性 可以;
++X; 不允许修改值
X+1; 可以 这是新的int值
<img alt="1667536090839" loading="lazy">
6.抽象类
基础:
- 标志: abstract 修饰类和方法 就称为抽象类 或者抽象方法
- 抽象方法必须在抽象类中
- 抽象方法的特点: 没有方法体 使用abstract修饰
- 抽象类的价值多用于设计,设计好后,让子类进行继承 并实现抽象类
- 在框架和设计模式中使用居多.
抽象类 父类的方法不确定性 .
比如 animal 一定有eat方法 但是不需要写具体的实现方法 而是完全交给父类去实现.
抽象类一般会被继承 由子类实现具体功能- abstract class Animal{
- private String name;
- public Animal(String name) {
- this.name = name;
- }
- //父类方法不确定性 就是没有方法体
- /*public void eat(){
- }*/
- //同时 类也需要写成抽象类
- public abstract void eat();
- }
复制代码 抽象类细节:
- 抽象类 不能被实例化
- 抽象类不一定包含abstract方法.
- 一旦有抽象(abstract)方法 就一定要声明为抽象类
- abstract 只能修饰类和方法 不能修饰属性和其他
- 抽象类 还是一个类 可以有所以成员 比如 : 非抽象方法 属性 方法块 构造器等.
- 抽象方法里不能有方法体
- 继承抽象类 要么是子类变成抽象类 或者 实现所有抽象方法 抽象类只能由抽象类继承,抽象方法强制实现
- 抽象方法不能使用private final 和static 关键字 因为子类 私有的(本类使用) final (最终的不能修改) static 是和重写无关的关键字
抽象类课堂练习
1.final 不能通过 fianl 不能继承 不能重写
2.static 不能通过 static 与方法重写无关
3.private 不能通过 权限问题
4, 就是子类继承父类 但是必须实现父类的方法.
<img alt="1667537819863" loading="lazy">
7.模板设计模式(抽象类 抽象方法的案例)
- package abstract_;
- /**
- * @Auther: qianl
- * @Date: 2022/11/4 13:11
- * @Description:
- */
- public class Abstract02 {
- public static void main(String[] args) {
- new AA().jobTime();
- //消耗时间15
- new BB().jobTime();
- //BB消耗的时间15
- }
- }
- abstract class TestTemplate{
- //计算某段代码的消耗时间
- public void jobTime() {
- //获取时间
- long start = System.currentTimeMillis();
- job();//动态绑定机制 子类调用就会绑定子类方法
- long end = System.currentTimeMillis();
- System.out.println("AA消耗的时间" + (end - start));
- }
- //抽象方法
- public abstract void job();
- }
- class AA extends TestTemplate{
- @Override
- public void job() {
- long num = 0;
- for (int i = 1; i <= 100000000; i++) {
- num += 1;
- }
- }
- }
- class BB extends TestTemplate{
- @Override
- public void job() {
- long num = 0;
- for (int i = 1; i <= 100000000; i++) {
- num += 1;
- }
- }
- }
复制代码 匿名内部类的最佳实践:
当做实参直接传递, 简洁高效 方法中传入匿名内部类 直接实现接口 注意写法- //默认实现方法
- default void dosm(){
- //公有功能
- }
- //静态方法
- public static demo(){
-
- }
复制代码 练习:
<img alt="1667816274764" loading="lazy">- package java基本知识点复习;
-
- public class 初始化块初始化静态变量 {
- //非静态初始化块能初始化静态变量,也可以初始化实例变量。(顺序问题但是前提是得通过实例化来调用构造方法)
- //静态初始化块可以初始化静态变量,但是不能初始化实例变量。和静态初始化块的加载时间有关。
-
- static int i,j;
- int k=0;
- //非静态初始化
- {
- System.out.println("输出结果");
- i=5;
- System.out.println(i);
- k=6;//内存中还没有这个k变量,非静态变量依赖于对象存在
- System.out.println(k);
- }
-
- //静态初始化块
- static{
- j=6;
- // k=0;
- System.out.println("静态代码块");
- }
-
-
- public static void main(String[] args) {
- System.out.println(i);
- System.out.println(j);
- //11 初始化块初始化静态变量 AA=new 初始化块初始化静态变量();
-
- }
-
- }
复制代码 成员内部类 在外部类的成员位置上
写在外部类的成员位置上面, 可以直接访问外部类的所有成员.
外部类调用内部类的方法是 new对象
其他外部类 调用方法也是 new 对象 Outer().Inner inner = new Outer().Inner();
因为是成员 所以所有修饰符都可以使用public protected 默认 private
- 可以使用修饰符
- 在外部类的成员属性位置上,可以直接访问外部类的所有成员,包括private属性
- 作用域, 使用方式是new对象在调用方法.
非静态成员内部类(没有static)
- //接口
- public interface AInterface {
- //属性
- public int n1 = 10;
- //方法
- public void hi();
- //1.8以后 可以使用default关键字修饰
- default public void ok(){
- System.out.println("is OK..");
- }
- //静态方法
- public static void cry(){
- System.out.println("cry...");
- }
- }
- //测试类
- public class Interface {
- public static void main(String[] args) {
-
- new A().hi();
- //可以使用接口的默认方法
- new A().ok();
- //静态方法需要静态调用 类.方法名
- AInterface.cry();
- }
- }
- //接口的实现类
- class A implements AInterface{
- @Override
- public void hi() {
- System.out.println("say hi");
- }
- }
复制代码 静态成员内部类(有static)
//静态内部类
//1.放在成员变量的位置,
//2.使用static修饰
//3.可以直接访问外部类的静态成员,包括私有属性,但是不能访问非静态的
//4.可以添加修饰符(public protected 默认 private) 地位是一个成员
//5.访问方法 新建一个类
//6,如果存在同名属性 就近原则 要使用外部类的属性 因为是静态的 所以可以直接 类名.属性名
//注意一点细节:
静态内部类中不能创建静态属性
因为先加载外部类的静态属性 然后加载内部类 而如果加了静态属性 那就会和外部类一起创建 会报错
Inner classes cannot have static declarations
内部类不能声明静态属性- 1. 现在要制作战斗机\武装直升机 专家只需要把飞船需要的功能 或者规格 定下来 即可, 然后让人去具体实现即可. 规格或者范例
- 2. 一个项目经理 管理三个程序员 ,功能开发一个软件 为了控制和管理软件 项目经理 可以定义一些接口 ,然后由程序员去具体实现. (主要是规范方法名,方法属性,控制功能质量.)
- 3. 三个程序员,编写三个类 分别完成对Mysql Oracle DB2数据库的连接 donnect close...
复制代码 <img alt="1668792235292" loading="lazy">
test测试:
输出结果:1.调用外部类构造器
输出s2.a 就是输出 5
r.a 还是5
<img alt="1668792489642" loading="lazy">
第二章:枚举类 enumeration(枚举 简写enum)
导入
预设一个场景:
Season类 季节类 只有- package abstract_;
- //实现类
- public class DBInterface {
- public static void main(String[] args) {
- MysqlDB mysqlDB = new MysqlDB();
- UseDB useDB = new UseDB();
- useDB.useDB(mysqlDB);
- }
- }
- //具体实现
- class MysqlDB implements DB{
- @Override
- public void connect() {
- System.out.println("连接Mysql");
- }
- @Override
- public void close() {
- System.out.println("退出Mysql");
- }
- }
- //调用
- class UseDB{
- public void useDB(DB db){
- db.connect();
- db.close();
- }
- }
- //接口 public abstract都是默认的
- interface DB{
- void connect();
- void close();
- }
复制代码 枚举的特点
- 枚举是一组常量的集合
- 枚举属于一种特殊的类,里面只包含一组有限的特定的对象
特点与演示
实现枚举的两种方式
- 自定义枚举
- 构造器私有化
- 本类内部创建一组对象
- 对外暴露对象(使用public static final 修饰符)
- 不提供set方法 只提供get方法
- 使用enum实现
- 使用 enum 代替 class
- 直接使用 SPRING("春天","舒适"); 这样创建对象
- 多个使用","号分隔
- 需要写在 成员属性的 前面
- 实际展示:
- interface B{
- void test;
- }
- class A implement B{
- public void test(){
- System.out.println("A的test实现")
- }
- }
- class C implement B{
- public void test(){
- System.out.println("C的test实现")
- }
-
- class D {
- public void (A a){
- System.out.println(a.test);
- }
- }
复制代码- Usb usb = new Usb[2];
- usb[0] = new Phone();
- usb[1] = new Camera();
- //遍历实现接口的固定方法 然后实现特有方法
- for(int i = 0 ; i< usb.length; i++){
- //都是动态绑定
- usb[i].start();
- usb[i].end();
- //确定继承关系 并实现特有方法
- if(usb[i] instanceof Phone){
- ((Phone)usb[i]).call();
- }
- }
复制代码 细节
enum关键字的细节问题:
- 使用enum关键字, 自动继承 Enum类
( ctrl+H 查看父辈 只有Object 不行) ( instanceof enum 不行 报错(Expression expected) 应为 预期 表达式)
在enum类中写判断可以显示- interface A{}
- class B implement A{}
- class C implement A{}
- main方法{
- A a1 = new B();
- A a2 = new C();
- a1.test();
- a2.test();
- }
- test (A a){
- //这里就能传入 A类型 B类型 C类型的对象了 那么只要写一个接口的方法(父类的方法) 就能实现旗下所有子类的方法 (使用向下转型和判断 也能使用接口的 默认方法 静态方法)
- }
- 多态传递则是
- interface A{}
- //B接口继承了A接口
- interface B extends A{}
- // test类 相当于 实现 A 与 B两个接口
- class test implement B{}
复制代码 IDEA 指着enum 这个也能显示 继承的是 Enum 这个泛型 里显示的是包名
老韩 是使用javap 来显示
<img alt="1668798599239" loading="lazy">
显示 注意 这个类是final 属性的 继承了Enum泛型
<img alt="1668798771768" loading="lazy">
- public static final 类名 对象名 = new 类名("属性"); 简化成了 类名("属性"); 但是 必须要知道是调用了那个构造器
也就是 必须要有该构造器
- 如果使用无参构造器 创建枚举对象,则实参列表和小括号都可以省略.
- package abstract_;
- /**
- * @Auther: qianl
- * @Date: 2022/11/5 18:25
- * @Description:
- */
- public class InterfaceAndExtends {
- public static void main(String[] args) {
- LittleMoney littleMoney = new LittleMoney("大圣");
- littleMoney.kufu();
- //大圣 会功夫
- littleMoney.fly();
- littleMoney.flying();
- littleMoney.sim();
- littleMoney.swimming();
- /*
- bird的默认飞行
- 小猴子实现bird飞的方法
- 重写小猴子的默认方法
- 大圣实现的游泳方法
- */
- }
- }
- //猴子父类
- class Money{
- private String name;
- public Money(String name) {
- this.name = name;
- }
- public void kufu(){
- System.out.println(name+" 会功夫");
- }
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- }
- interface Fish{
- //静态方法 不能重写
- static void sim01(){
- System.out.println("fish的默认方法");
- }
- //默认方法 可以重写!
- default void sim(){
- System.out.println("会游泳");
- }
- //游泳方法
- void swimming();
- }
- interface bird{
- default void fly(){
- System.out.println("bird的默认飞行");
- }
- void flying();
- }
- //小猴子继承了猴子 但是不能继承和实现其他方法了
- //子类继承父类 自动获得父类的功能 和接口的默认方法
- //子类需要拓展功能 可以通过实现接口来拓展
- // 接口的多继承(实现 ) 可以对java单继承继续一定的补充.
- class LittleMoney extends Money implements Fish,bird{
- public LittleMoney(String name) {
- super(name);
- }
- //默认方法也能继承和重写
- @Override
- public void sim() {
- System.out.println("重写小猴子的默认方法");
- }
- @Override
- public void swimming() {
- System.out.println(getName() + "实现的游泳方法");
- }
- @Override
- public void flying() {
- System.out.println("小猴子实现bird飞的方法");
- }
- }
复制代码 - 当有多个枚举对象时,使用逗号间隔 最后需要分号收尾.
- interface A01{
- int x = 1;
- }
- class B01{
- int x = 2;
- }
- class b extends B01 implements A01{
- public void pX(){
- System.out.println(super.x);
- System.out.println(A01.x);
- }
- }
复制代码 - 枚举对象必须在枚举类的行首.
练习
题1: OK
自带无参构造
枚举类 Gender 没有属性
BOY 和GIRL两个枚举对象
<img alt="1668799259645" loading="lazy">
题2:
输出的是BOY 也就是调用了Gender2 的父类 Enum 的toString方法 返回的是"return name";
因为指向的是同一个对象 == 对引用类型判断的是地址 所以是 TRUE
Enum的成员方法
- 使用关键字 enum时, 会隐式继承Enum类, 这样我们就可以使用Enum类相关的方法. 因为子类自动继承父类的所有成员方法.
- <img alt="1668876914033" loading="lazy">
- enum常用方法一览表
- values(), ordinal() 和 valueOf() 方法
enum 定义的枚举类默认继承了 java.lang.Enum 类,并实现了 java.lang.Serializable 和 java.lang.Comparable 两个接口。
values(), ordinal() 和 valueOf() 方法位于 java.lang.Enum 类中:
- values() 返回枚举类中所有的值。(数组)
- ordinal()方法可以找到每个枚举常量的索引,就像数组索引一样。(索引下标)
- valueOf()方法返回指定字符串值的枚举常量。(返回对象常量)
<img alt="1668877267789" loading="lazy">
- toString方法 返回的是当前对象名
<img alt="1668880296766" loading="lazy">- feed(Cat cat){ ... }
- feed(Dog dog){ ... }
复制代码 enum课堂练习
题1:
<img alt="1668882626448" loading="lazy">
如下- feed(Animal animal){ ... }
- Animal dog1 = new Dog(); //父类引用指向子类对象
- Animal cat1 = new Cat();
- feed(dog1);
- feed(cat1);
复制代码 enum实现接口
- 由于 enum 已经继承了Enum这个类 java中单继承 所以不能进行再继承其他的类
- 但是枚举类依旧是一个类 可以实现接口 也就是继承接口
第三章:注解(Annotation)
导入
- 注解 又称为 元数据(Metadata) 用来修饰 包\ 类\ 方法\ 属性\ 构造器\ 局部变量 等数据信息
- 和注释一样 并不会影响程序逻辑 但是注解可以被编译或运行, 相当于在代码中的补充信息.
- 在javaSE中 注解的目的简单 标记过时的功能 忽略警告灯 在JavaEE中 比较重要 可以代替繁冗代码和XML配置
JDK中的基本注解
@Override 重写方法
重写方法 只能用于方法
如果写了@Override 如果有这个 编译器就会去检查是否真的重写了该方法 重写了就通过, 否则编译不通过
**其中的@interface 表示 注解类 ** jdk5.0加入的
<img alt="1668884717488" loading="lazy">
ElementType.Method(方法) 要素类型: 方法
<img alt="1668884428945" loading="lazy">
@Deprecated 标记过时
标记过时 比如打印当前时间
标记的元素已经过时 不推荐使用 但是依然可以使用.保持: 保留策略 点 "运行时间"
要素类型: 构造函数,字段,本地(局部)_变量,方法,包,参数,类型
constructor, field, local_variable, method, package, parameter, type
@Documented 的作用可以做到新旧版本的兼容和过度@SuppressWarnings 抑制警告
注解的使用有以下三种:
unchecked 抑制没有进行类型检查操作的警告
- 抑制单类型的警告:@SuppressWarnings("unchecked")
- 抑制多类型的警告:@SuppressWarnings("unchecked","rawtypes")
- 抑制所有类型的警告:@SuppressWarnings("all")
- 抑制没有使用的警告: @SuppressWarnings("unused")
可以直接放在main方法的最上面 这样范围就是整个main了
关键字用途all抑制所有警告boxing抑制装箱、拆箱操作时候的警告cast抑制映射相关的警告dep-ann抑制启用注释的警告deprecation抑制过期方法警告fallthrough抑制在 switch 中缺失 breaks 的警告finally抑制 finally 模块没有返回的警告hiding抑制相对于隐藏变量的局部变量的警告incomplete-switch忽略不完整的 switch 语句nls忽略非 nls 格式的字符null忽略对 null 的操作rawtypes使用 generics (泛型) 时忽略没有指定相应的类型restriction抑制禁止使用劝阻或禁止引用的警告serial忽略在 serializable 类中没有声明 serialVersionUID 变量static-access抑制不正确的静态访问方式警告synthetic-access抑制子类没有按最优方法访问内部类的警告unchecked抑制没有进行类型检查操作的警告unqualified-field-access抑制没有权限访问的域的警告unused抑制没被使用过的代码的警告抑制警告 源码:
范围 TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE
该注解类 有数组 String[] values() 设置一个数组 比如: {"unchecked","rawtypes","unused"}- class Outer{//外部类
- class Inner{ //内部类
-
- }
- }
- class Other{} //外部其他类
复制代码 <img alt="1668884062342" loading="lazy">
四种元注解
元注解 就睡修饰其他的注解:
本身作用不大:
@Retention 注解的作用范围
source 来源 class 加载 runtime 运行时
source 编译器将丢弃注释 (编译文件 也就是java源文件)
class 注释将由编译器记录在类文件中,但VM在运行时不需要保留注释。这是默认行为。(默认值)
类文件 .class文件
runtime 注释将由编译器记录在类文件中,并在运行时由VM保留,因此可以反射地读取。
运行到JVM
<img alt="1669060376349" loading="lazy">- public class Outer01{
- private int outer01 = 10;
- private void m2() {}
- //局部内部类
- public void m1() {
- //局部内部类是定义在外部类的局部位置,通常在方法中
- class Inner02 {
- //可以直接访问外部类的所有成员,包含私有的
- private int outer01 =100;
- public void f1() {
- //就近原则 属性名同名就近原则
- System.out.println("局部内部类调用private属性" + outer01);
- //单独的this.outer01 指的是 Inner02 的属性
- System.out.println("调用外部类的私有属性" + Outer01.this.outer01);
- m2(); //可以直接调用私有方法
- new Inner01().Test(); //new 一个成员内部类
- }
- }
- //可以直接在方法内 新建对象的方式 使用该类
- Inner02 inner02 = new Inner02();
- inner02.f1();
- }
- public void Test02() {
- //new Inner02() 因为是在方法中写的内部类 所以必须在作用域内(m1方法中)使用.
- }
- }
复制代码 <img alt="1669059521706" loading="lazy">
@Target 指定注解在哪些地方使用
返回可应用批注类型的元素类型的数组。
返回的是一个可应用批注类型 的数组
要素类型: 构造函数,字段,本地(局部)_变量,方法,包,参数,类型
constructor, field, local_variable, method, package, parameter, type- new 类或接口(参数列表){
- 类体
- }
- Anonymous 匿名的
复制代码 @Documented 指定该注解是否会在javadoc体现
Documented (记录在案的)
如果一个注解@B,被@Documented标注,那么被@B修饰的类,生成文档时,会显示@B。如果@B没有被@Documented标准,最终生成的文档中就不会显示@B。
被标注则记录 否则不记录
作用范围: 注释类型 只能针对注释- //基于接口的匿名内部类
- //1.需求: 想使用接口A,并创建对象
- //2.传统方法, 写一个类,实现该接口,并创建对象
- //3.我只想用一次,不想再次使用,这个类不想多次使用.
- //4.匿名内部类 简化开发
- //5.tiger编译类型 A() 运行类型 就是匿名内部类
- //底层其实有名字的 叫Outer$1
- //6.jvm底层在创建匿名内部类Outer$1,立刻创建了Outer$1实例,并把地址传给了tiger
- //7.匿名内部类只会使用一次,就不再使用 类Outer$1就消失了 但是对象tiger能无限使用
复制代码 @Inherited 子类会继承父类注解
Inherited 继承
标注了 则 父类注解 子类会继承 否则不继承 子类会自动获得该注解
针对注解类型- package InnerClass_;
- /**
- * @Auther: qianl
- * @Date: 2022/11/5 23:14
- * @Description:
- */
- public class Anonymous_ {
- public static void main(String[] args) {
- new Outer().method();
- }
- }
- class Outer{//外部类
- private int i1 = 10;//属性
- public void method(){//方法
- //基于接口的匿名内部类
- //1.需求: 想使用接口A,并创建对象
- //2.传统方法, 写一个类,实现该接口,并创建对象
- //3.我只想用一次,不想再次使用,这个类不想多次使用.
- //4.匿名内部类 简化开发
- //5.tiger编译类型 A() 运行类型 就是匿名内部类
- //底层其实有名字的 叫Outer$1
- /*
- class Outer$1 implement A{
- @Override
- public void cry() {
- System.out.println("老虎叫...");
- }
- }
- */
- A tiger =new A(){
- @Override
- public void cry() {
- System.out.println("老虎叫...");
- }
- }; //是方法所以要分号
- //idea中没显示名字 而在文档资源管理器 中有对应的class文件.
- System.out.println("匿名内部类的运行类型"+getClass().getName());
- //class InnerClass_.Outer
- tiger.cry();
- }
- }
- interface A{//接口
- void cry();
- }
- class Father{//类
- public Father(String name){//构造器
- }
- public void test(){//方法
- }
- }
复制代码 <img alt="1668974327942" loading="lazy">
静态的练习:
题1:
输出结果:
- 对象 c price = 9.0; color = "red"
- 对象 c1 price = 100.0 ; color = "white" 但是它是静态属性 被修改过了 变成了 red
<img alt="1669060543589" loading="lazy">
题2:- //生成匿名内部类 Outer$2
- //生成并返回给father 并且"father" 这个参数会传递给构造器
- Father father =new Father("father"){
- @Override
- public void test() {
- System.out.println("匿名内部类基于类重写test()");
- }
- };
- father.test();
复制代码 <img alt="1669060793964" loading="lazy">
题3:- //抽象类的匿名构造器 Outer$3
- abClass abclass =new abClass(){
- @Override
- void cry() {
- System.out.println("抽象类匿名构造器重写方法cry()");
- }
- };
- abclass.cry();
复制代码 <img alt="1669065533330" loading="lazy">
内部类练习:
题4:- //默认继承类 就是Outer$1 extends A{}
- //1.第一种匿名内部类调用方法 直接调用
- new A(){
- @Override
- public void cry(){
- sout("hello~");
- }
- }.cry();
- //2.第二种匿名内部类方法 创建一个新对象
- A a = new A(){
- @Override
- public void cry(){
- sout("hello~");
- }
- };
- a.cry(); //动态绑定, 运行类型是Outer$1
复制代码 <img alt="1669210902782" loading="lazy">
题5:- interface AA{
- public void cry();
- }
- main方法中:
- public static void show(AA aa){
- aa.cry();
- }
- //匿名内部类
- show(new AA(){
- public void cry(){
- sout("AA cry")
- }
- });
- //show方法中 传入一个匿名内部类
- public class AnonymousTest_ {
- public static void main(String[] args) {
- //注意 AnonymousTest_$1 implement AA()
- //调用方法 传入匿名内部类
- show(new AA(){
- public void cry(){
- System.out.println("AA cry");
- }
- });
-
- show(new AA(){
- public void cry(){
- System.out.println("另一个实现AA的cey方法");
- }
- });
-
- //传统方法
- show(new BB());
- }
- //静态方法 将传入的类 调用cry()方法 动态绑定 绑定匿名内部类的cry()方法
- public static void show(AA aa){
- aa.cry();
- }
- }
- interface AA{
- public void cry();
- }
- //(硬代码) 因为每次实现cry 都需要新建一个类 而且不好随意填加修改.
- class BB implements AA{
- @Override
- public void cry() {
- System.out.println("传统方法实现接口");
- }
- }
复制代码 <img alt="1669210535590" loading="lazy">
题6:- package InnerClass_;
- import extend_.improve.Base;
- /**
- * @Auther: qianl
- * @Date: 2022/11/7 18:13
- * @Description:
- */
- public class InnerClass02_ {
- public static void main(String[] args) {
- CellPhone cellPhone = new CellPhone();
- //1.传递的是失恋了Bell的匿名内部类
- //2.重写了ring
- //3.方法中的 Bell bell = new Bell(){ 重写方法 };
- cellPhone.alarmclock(new Bell() {
- @Override
- public void ring() {
- System.out.println("懒猪起床了");
- }
- });
- cellPhone.alarmclock(new Bell() {
- @Override
- public void ring() {
- System.out.println("小伙伴上课了");
- }
- });
- }
- }
- interface Bell{
- void ring();
- }
- class CellPhone{
- public void alarmclock(Bell bell){
- bell.ring();
- }
- }
复制代码 <img alt="1669213528756" loading="lazy">
<img alt="1669212256069" loading="lazy">
题7:
注意: 要习惯 以某个类为方法的返回类型- package InnerClass_;
- /**
- * @Auther: qianl
- * @Date: 2022/11/8 12:40
- * @Description:
- */
- public class MemberInnerClass_ {
- public static void main(String[] args) {
- OuterClass_ outerClass_ = new OuterClass_();
- outerClass_.show();
- //通过已有的外部类实例 新建一个内部类 成员内部类可以 点 出来
- OuterClass_.InnerClass_ o_i01 = outerClass_.new InnerClass_();
- o_i01.say();
- //通过新建对象获取成员内部类 新建类的新建类
- OuterClass_.InnerClass_ o_i = new OuterClass_().new InnerClass_();
- o_i.say();
- //通过方法获取成员内部类
- OuterClass_.InnerClass_ outerClass_innerClass_ = outerClass_.getInnerClass_();
- outerClass_innerClass_.say();
- }
- }
- class OuterClass_{
- private String name = "外部私有属性";
- private void hi(){
- System.out.println("hi");
- }
- public class InnerClass_{
- private double i = 99.9;
- private String name = "内部私有属性";
- public void say(){
- //如果重名 会就近原则 需要使用类名.this.属性来获取
- System.out.println(OuterClass_.this.name + "内部私有属性: "+i);
- hi();
- }
- }
- public void show(){
- System.out.println("show the InnerClass_().say()");
- new InnerClass_().say();
- }
- //方法 返回成员内部类
- public InnerClass_ getInnerClass_(){
- return new InnerClass_();
- }
- }
复制代码 注意指向的地方是不一样的 所以地址不同
<img alt="1669925472434" loading="lazy">
测试题:
题目1:
String的equals 重写过 比较的是内容(True)
== 比较的是对象地址 因为都是直接赋值 比较的是常量池的对象 (True)
<img alt="1669925589476" loading="lazy">
题目2:
- equals(重写过)比较的内容 //T
- ==比较的地址 a是常量池 b是堆 //F
- b.intern() 就是返回来自 常量池的字符串 那么 a == b.intern() ==比较地址 a的地址是常量池 b.intern() 也是常量池 //T
- b是堆 b.intern()是常量池 所以是 // F
<img alt="1669926108484" loading="lazy">
<img alt="1669925819355" loading="lazy">
题目3:
- s2 == s3 比较地址 s2直接赋值,指向常量池, s3新建对象,指向堆 //F
- s2 == s4 比较地址 都是直接赋值 都指向常量池 //T
- s2.equals(s3) String重写了 比较内容 //T
- s1 == s2 //F
<img alt="1669927342461" loading="lazy">
题目4:
注意: p1.name = "hspedu" 就是String name = "hspedu" 直接赋值
- String的 的quals比较内容 //T
- p1.name == p2.name 比较地址 都指向同一个常量池 //T
- p1.name == "hspedu" 转化为比较内容 //T
- s1 == s2 比较的堆里的地址 //F
<img alt="1669927514092" loading="lazy">
字符串的特性:
<img alt="1669927756305" loading="lazy">
String s1 = helllo 在 常量池 因为是直接赋值
s1 = haha hello不会消失 而是s1 指向常量池新的字符串
创建了两个对象
String是final类 字符串不可变,但内容可变
String面试题:
1.编译器做了优化,判断创建的常量池对象 是否有引用指向 就是创建了给谁用的- package InnerClass_;
- /**
- * @Auther: qianl
- * @Date: 2022/11/19 00:37
- * @Description:
- */
- public class StaticInnerClass_ {
- public static void main(String[] args) {
- Outer10 outer10 = new Outer10();
- outer10.show();
- //新建一个内部类 注意 静态内部类不能通过 点new 的方式
- Outer10.Inner01 inner01 = new Outer10.Inner01();
- inner01.say();
- //使用调用静态方法的方式使用
- System.out.println("++++++");
- Outer10.Inner01 inner011 = Outer10.getInner01();
- inner01.say();
- //使用外部类的调用非静态属性
- System.out.println("+++++++");
- Outer10.Inner01 inner012 = outer10.getInner01_();
- inner012.say();
- }
- }
- class Outer10 {
- private int n1 = 10;
- private static String name = "张三";
- //静态内部类
- //1.放在成员变量的位置,
- //2.使用static修饰
- //3.可以直接访问外部类的静态成员,包括私有属性,但是不能访问非静态的
- //4.可以添加修饰符(public protected 默认 private) 地位是一个成员
- //5.访问方法 新建一个类
- public static class Inner01 {
- public void say() {
- System.out.println("这是外部类静态属性" + name);
- }
- }
- public void show() {
- System.out.println(n1);
- Inner01 inner01 = new Inner01();
- inner01.say();
- }
- public Inner01 getInner01_() {
- return new Inner01();
- }
- public static Inner01 getInner01() {
- return new Inner01();
- }
- }
复制代码 2.题目二
一共三个对象 a b (池) c(堆)
看源码 先是new 一个StringBuilder sb= new StringBuilder
String value[]中 添加hello这个对象
然后使用sb.append 加在常量池中
然后添加abc 在value中
使用sb.append 加在常量池中
然后c = a+b (不是直接赋值) 检查c 也就是"helloabc" 是否存在常量池 没有则添加 到常量池
然后将地址给堆
c指向堆
注意: 直接赋值 " " 对象指向常量池 否则对象指向在堆中- //对于季节而言,他的对象(具体值)只有四个 不会更多
- //这个不能提醒其是四个固定的对象
- //这时候使用枚举类 一个一个举例 将具体的对象一个一个举例出来
- //创建的Season对象 四个固定对象(值) 而且是只读 不需要修改的
复制代码 <img alt="1670164930510" loading="lazy">
<img alt="1670164791124" loading="lazy">
题目三:
s1 常量池
s2 常量池
s5 常量池
s6 堆 赋予的是 "hspedujava" 在常量池的地址
但是s6获取的是 .intern() 返回的是常量池里的对象
s5==s6 真
s5.equals(s6) 比较内容 真
<img alt="1670165792368" loading="lazy">
题目四:
str指向池中地址
ch 是数组 在存在堆中 ch也指向的是堆中的数组[java]
调用ex方法 就会生成一共新栈
//注意 str是一个形式参数 也就是复制了值"hsp" 过来而已 不会更改原本的
str是直接赋值 指向常量池里的一个新值
ch[0] = 'h' 那么ch的值就变成了 hava
那么最后结果是 hsp and hava
注意: final 是指向的地址不能改变 那么 final int i = 3.14 ;不可更改 地址在栈
final int[] i = [1,2,3,4] 地址不能更改 地址在堆 但是值可以改变
<img alt="1670165960382" loading="lazy">
String常用方法
1char charAt(int index) 返回指定索引处的 char 值。2int compareTo(Object o) 把这个字符串和另一个对象比较。3int compareTo(String anotherString) 按字典顺序比较两个字符串。4int compareToIgnoreCase(String str) 按字典顺序比较两个字符串,不考虑大小写。5String concat(String str) 将指定字符串连接到此字符串的结尾。6boolean contentEquals(StringBuffer sb) 当且仅当字符串与指定的StringBuffer有相同顺序的字符时候返回真。7[static String copyValueOf(char] data) 返回指定数组中表示该字符序列的 String。8[static String copyValueOf(char] data, int offset, int count) 返回指定数组中表示该字符序列的 String。9boolean endsWith(String suffix) 测试此字符串是否以指定的后缀结束。10boolean equals(Object anObject) 将此字符串与指定的对象比较。11boolean equalsIgnoreCase(String anotherString) 将此 String 与另一个 String 比较,不考虑大小写。12[byte] getBytes() 使用平台的默认字符集将此 String 编码为 byte 序列,并将结果存储到一个新的 byte 数组中。13[byte] getBytes(String charsetName) 使用指定的字符集将此 String 编码为 byte 序列,并将结果存储到一个新的 byte 数组中。14[void getChars(int srcBegin, int srcEnd, char] dst, int dstBegin) 将字符从此字符串复制到目标字符数组。15int hashCode() 返回此字符串的哈希码。16int indexOf(int ch) 返回指定字符在此字符串中第一次出现处的索引。17int indexOf(int ch, int fromIndex) 返回在此字符串中第一次出现指定字符处的索引,从指定的索引开始搜索。18int indexOf(String str) 返回指定子字符串在此字符串中第一次出现处的索引。19int indexOf(String str, int fromIndex) 返回指定子字符串在此字符串中第一次出现处的索引,从指定的索引开始。20String intern() 返回字符串对象的规范化表示形式。21int lastIndexOf(int ch) 返回指定字符在此字符串中最后一次出现处的索引。22int lastIndexOf(int ch, int fromIndex) 返回指定字符在此字符串中最后一次出现处的索引,从指定的索引处开始进行反向搜索。23int lastIndexOf(String str) 返回指定子字符串在此字符串中最右边出现处的索引。24int lastIndexOf(String str, int fromIndex) 返回指定子字符串在此字符串中最后一次出现处的索引,从指定的索引开始反向搜索。25int length() 返回此字符串的长度。26boolean matches(String regex) 告知此字符串是否匹配给定的正则表达式。27boolean regionMatches(boolean ignoreCase, int toffset, String other, int ooffset, int len) 测试两个字符串区域是否相等。28boolean regionMatches(int toffset, String other, int ooffset, int len) 测试两个字符串区域是否相等。29String replace(char oldChar, char newChar) 返回一个新的字符串,它是通过用 newChar 替换此字符串中出现的所有 oldChar 得到的。30String replaceAll(String regex, String replacement) 使用给定的 replacement 替换此字符串所有匹配给定的正则表达式的子字符串。31String replaceFirst(String regex, String replacement) 使用给定的 replacement 替换此字符串匹配给定的正则表达式的第一个子字符串。32[String] split(String regex) 根据给定正则表达式的匹配拆分此字符串。33[String] split(String regex, int limit) 根据匹配给定的正则表达式来拆分此字符串。34boolean startsWith(String prefix) 测试此字符串是否以指定的前缀开始。35boolean startsWith(String prefix, int toffset) 测试此字符串从指定索引开始的子字符串是否以指定前缀开始。36CharSequence subSequence(int beginIndex, int endIndex) 返回一个新的字符序列,它是此序列的一个子序列。37String substring(int beginIndex) 返回一个新的字符串,它是此字符串的一个子字符串。38String substring(int beginIndex, int endIndex) 返回一个新字符串,它是此字符串的一个子字符串。39[char] toCharArray() 将此字符串转换为一个新的字符数组。40String toLowerCase() 使用默认语言环境的规则将此 String 中的所有字符都转换为小写。41String toLowerCase(Locale locale) 使用给定 Locale 的规则将此 String 中的所有字符都转换为小写。42String toString() 返回此对象本身(它已经是一个字符串!)。43String toUpperCase() 使用默认语言环境的规则将此 String 中的所有字符都转换为大写。44String toUpperCase(Locale locale) 使用给定 Locale 的规则将此 String 中的所有字符都转换为大写。45String trim() 返回字符串的副本,忽略前导空白和尾部空白。46static String valueOf(primitive data type x) 返回给定data type类型x参数的字符串表示形式。47contains(CharSequence chars) 判断是否包含指定的字符系列。48isEmpty() 判断字符串是否为空。<img alt="1670166822405" loading="lazy">
StringBuffer
StringBuffer 基本信息
注意 : StringBuffer 可变长字符序列
<img alt="1670168319229" loading="lazy">
注意: StringBuffer 是一个可边长的字符序列 可以串行化
和String一样 有一共value[]
但是 不是final类 也就是不写在常量池 而是写在堆中
StringBuffer 是final 类 不能被继承
超出长度才会更改地址 所以不用每次创建新对象 效率高
<img alt="1670168932501" loading="lazy">
String VS StringBUffer
- 不可变 VS 可变
- 常量池 VS 堆
- 不用每次都去更新地址 除非超过长度
<img alt="1670168607124" loading="lazy">
StringBuffer 构造器
默认初始化是16个字符
StringBuffer(){
super(16);
}
<img alt="1670169002891" loading="lazy">
//指定 char[] value 的大小
<img alt="1670169377845" loading="lazy">
//3. 字符串的大小 + 16- //演示自定义枚举类
- class Season {
- private String name;
- private String desc;//描述
- public static final Season SPRING = new Season("春天", "舒适");
- public static final Season SUMMER = new Season("夏天", "炎热");
- public static final Season AUTUMN = new Season("秋天", "凉爽");
- public static final Season WINTER = new Season("冬天", "寒冷");
- //1.先将构造器私有化,防止new
- //2.强调setXX方法,防止属性修改
- //3.在Season类内部创建静态类 , 直接创建固定的对象
- //4.优化 加入final 进行不可修改.
- private Season(String name, String desc) {
- this.name = name;
- this.desc = desc;
- }
- public String getName() {
- return name;
- }
- public String getDesc() {
- return desc;
- }
- }
复制代码 String转成StringBuffer类型
1.使用构造器 注意 不影响原有的str
2/先构建无参构造器然后, 使用append方法
<img alt="1670170403437" loading="lazy">
StringBuffer 转String类型
toString()方法 或者构造器
<img alt="1670170507787" loading="lazy">
StringBuffer方法(包含直接父类的方法)
操作数组一样 增删 改查
append 追加 可以追加数字 true 小数 等
返回的是StringBuffer
查: replace 没找到就返回-1
<img alt="1670170730059" loading="lazy">
StringBuffer练习:
<img alt="1670171256916" loading="lazy">
1.包装类是可以null的
2.如果str == null 那么给值="null"
所以长度为4
输出 null
直接构造器 输入str 创建对象时 会(0+16) 相当于 null.length() 空值异常
<img alt="1670171627543" loading="lazy">
<img alt="1670171380930" loading="lazy">
<img alt="1670171460403" loading="lazy">
练习2:
每三位分割
每三位加, 字符串处理
<img alt="1670171693877" loading="lazy">
<img alt="1670171782653" loading="lazy">- //演示使用enum关键字来实现枚举类
- enum Season2{
- //使用enum来实现枚举类
- //1.使用enum代替class
- //2,public static final Season2 SPRING = new Season2("春天", "舒适");
- //直接使用 Spring("春天","舒适");
- //3,多个常量(对象) 直接使用,号分隔.
- //4,要求将定义的常量对象, 写最前面
- SPRING("春天","舒适"),SUMMER("夏天", "炎热"),
- AUTUMN("秋天", "凉爽"),WINTER("冬天", "寒冷");
- private String name;
- private String desc;//描述
- private Season2(String name, String desc) {
- this.name = name;
- this.desc = desc;
- }
- public String getName() {
- return name;
- }
- public String getDesc() {
- return desc;
- }
- }
复制代码 StringBuilder
StringBuilder 基本信息
不保证同步! (不是线程安全的) 适用于单线程 单线程优先使用Stringbuilder类 以为比较快
<img alt="1670172474066" loading="lazy">
继承结构图: 和StringBuffer 一样
<img alt="1670172564492" loading="lazy">
注意: 由于没有做互斥 所以多线程会串线程
<img alt="1670173791551" loading="lazy">
由于String 每次使用都会变地址
<img alt="1670174083691" loading="lazy">
<img alt="1670174326823" loading="lazy">
类型字符序列效率线程内存String不可变字符序列低 每次修改重新定位地址--常量池StringBuffer可变长字符序列较高(增删)安全堆StringBuilder可变长字符序列高不安全(单线程)堆使用原则:
<img alt="1670174469567" loading="lazy">
StringBulider方法:
同StringBuffer
Math(数学相关)
基本信息:
当他是一个工具类就好 都是(static)静态方法! 所以都可以在主函数中直接调用
<img alt="1670174612284" loading="lazy">
Math方法:
ceilling(天花板)
ceil 向上取整 比如 -3.00009 取 -3.0 取>= 该参数的最小整数
floor 向下取整
round 四舍五入
sqrt 开方 只能大于0
random 返回的是0~1 [0,1) 的一个随机小数
找到固定值 使其随机的是一个固定值
取2-7的值 就是+1 十倍 就是+10 百倍 就是+100<img alt="1670175801377" loading="lazy">
<img alt="1670175256457" loading="lazy">
[table][tr]序号方法与描述[/tr][tr][td]1[/td][td]xxxValue() 将 Number 对象转换为xxx数据类型的值并返回。[/td][/tr][tr][td]2[/td][td]compareTo() 将number对象与参数比较。[/td][/tr][tr][td]3[/td][td]equals() 判断number对象是否与参数相等。[/td][/tr][tr][td]4[/td][td]valueOf() 返回一个 Number 对象指定的内置数据类型[/td][/tr][tr][td]5[/td][td]toString() 以字符串形式返回值。[/td][/tr][tr][td]6[/td][td]parseInt() 将字符串解析为int类型。[/td][/tr][tr][td]7[/td][td]abs() 返回参数的绝对值。[/td][/tr][tr][td]8[/td][td]ceil() 返回大于等于( >= )给定参数的的最小整数,类型为双精度浮点型。[/td][/tr][tr][td]9[/td][td]floor() 返回小于等于( |