相关链接
小技巧
- 在写一个类或者方法之前先明确思路,可以按照下边的思路来想.
- 需求:练习一个hello world程序
- 思路:(阐述大体实现流程)
- 定义一个类
- 定义一个主函数,为了让类独立运行
- 用输出语句在控制台输出hello world字样
- 步骤:(每一个想法具体怎么实现)
- 用class关键字完成类的定义.
- 用main函数写出主入口
- 用System.out.println输出相关语句
- 进制转换用倒序取余法(用于10进制和其他进制转换)
- 用Integer.MAX_VALUE可以获得int最大值
- Java是强类型语言,if的判断条件只能是boolean
- Java虚拟机在内存会默认开辟一定量空间,如果内存溢出,说明虚拟机开辟的空间不够,可以在开启虚拟机的时候修改配置,加大内存开辟空间
- 开发的时候要提高代码的复用性
- 数据多了可以用数组存起来,例如进制转换可以用数组存每一位.然后倒序输出.
- java中没有方法嵌套.不能在一个方法中再写一个方法.
常见名词解析
折叠代码块YAML
复制代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| 软件: 一系列按照特定顺序组织的计算机数据和指令的集合. DOS: Disk Operate System(磁盘操作系统) SUN: (Stanford University Network)斯坦福大学网络公司 Solaris: (SUN公司开发的系统) JVM: (Java Virtual Machine)Java虚拟机,可以实现Java语言跨平台 JRE: (Java Runtime Environment)Java运行时环境,包括JVM和核心类库 JDK: (Java Development Kit)系统开发工具包,包括JRE和开发工具 解释: JDK装完之后里边已经有了JRE的运行环境了,下边再装JRE,就相当于另装一个运行环境. SDK: (System Development Kit)系统开发工具包 JavaSE: 基础核心,用于面向对象,API,JVM JavaME: 移动端,用于嵌入式设备,被android替代 JavaEE: 面向企业,用于JSP Servlet 五大框架 交互方式: GUI: (Graphical User Interface) 图形化界面 CLI: (Command Line Interface) 命令行操作
|
JDK目录
折叠代码块YAML
复制代码
1 2 3 4 5 6 7 8 9 10 11 12 13
| JDK: Java开发工具包,包含了jre(运行环境,有jvm和核心类库) bin: (binary)存放可执行文件.java中的开发工具 javac: 编译工具(检查代码有没有错误,有错误报错,没错误编译,没有启动jvm) java: 执行工具(启动jvm,执行某类,然后将类加载到内存执行) jar: 打包工具 javadoc: 提取java文件中的文档注释,生成网页说明书 include: Java本地方法,调用C或C++底层文件 jre: Java运行环境.只用来运行环境 lib: 存放Java库文件(jar包) rt.jar: Java运行时所需文件,包含了java程序常用的包,java.lang,java.util,java.io等 tools.jar: Java编译类时用到(javac) dt.jar: Java的swing的包 src.zip: 存放了Java源码
|
CLASSPATH
- 没有配置该环境变量,java默认在当前目录寻找运行的class文件
- 配置后,java还会在CLASSPATH配置的目录中寻找相关class文件
- CLASSPATH配置的目录加
.会在当前目录找,不加也会在当前目录找,但需要其他路径加分号,加上.比较好,提高可阅读性.
dt.jar是swing的包,不用可以不加
tools.jar是编译时用的包,javac已经封装好该路径,也可以不用加
文档规范
折叠代码块YAML
复制代码
1 2 3 4 5
| 标识符: 就是变量名,可以用_和$来连接某些名称 注释: 可以用javadoc读取源码的文档注释生成源码说明书,javac编译的时候,注释不编译到字节码文件 文件名: 大驼峰 类名: 与文件名相同 main: 主程序入口
|
文档生成
- 类必须为
public
- 只读取文档注释,单行多行注释不提取
- 只提取
public和protected的成员信息,不提取private
- 文档注释可以加
@param和@return
折叠代码块BASH
复制代码
1 2 3
|
javadoc -d ./Tool Tool.java
|
基本数据类型
- Java的
char是两个字节,Java有8种基本数据类型,byte short int long float double char boolean
- Java的
char是使用unicode表的
- long型数据需要写l,float需要写f
- Java每一个大括号都是一个作用域,if大括号定义的变量,外部无法读取到.
- 类型不一致,内存空间就不一致.byte和int所占空间不同,运算的时候需要将小类型转换为大类型
![image]()
折叠代码块JAVA
复制代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| byte a = 4;
byte b1 = 4; byte b2 = 5; byte c = b1 + b2;
final byte b1 = 4; final byte b2 = 5; byte c = b1 + b2;
byte d = 1; int d2 = 2; int result = d + d2;
|
数据初值
- 基本类型中
char是\u0000(空格),boolean是false,其他都是0(\u表示unicode)
- 引用类型(例如String)初值都是null
- 计算机用补码存数据
变量
折叠代码块JAVA
复制代码
1 2 3
| int firstNumber; firstNumber = 1;
|
常量
折叠代码块JAVA
复制代码
1 2 3
|
final int NUMBER_FIRST = 1;
|
运算
- 两个整数做除法还是整数,想要小数就给末尾加个.0
异或(^): 看是不是不一样,不一样就是真
- 位
与(&), 位或(|), 异或同样可以运算boolean值
- &&和&,||和|
- 都是左边的符合条件就阻断,右边的需要两边都使用(位运算符)
- 程序的基本功能是处理数据
位运算符
- 左移 <<,右移 >>,无符号右移 >>>,与 &,或 |,异或 ^,取反 ~
- 位运算速度快
与&
特点
00101111 & 00001111(和1相与的地方可以取到原来数的位,与0相与则没有了)
作用
- 10进制转换为其他进制
- 取指定二进制位,可以用于二进制转到其他进制;
方式
- 10进制转换为其他进制
折叠代码块JAVA
复制代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
| int decimal = 55;
int binary = 0b110111;
int octal = 067;
int hex = 0x37;
decimal = 55; StringBuilder result_1 = new StringBuilder(); while (decimal != 0) { result_1.insert(0, String.valueOf(decimal & 1)); decimal >>= 1; } System.out.println(result_1.insert(0, "0b").toString());
decimal = 55; StringBuilder result_2 = new StringBuilder(); while (decimal != 0) { result_2.insert(0, String.valueOf(decimal & 7)); decimal >>= 3; } System.out.println(result_2.insert(0, "0").toString());
decimal = 55; StringBuilder result_3 = new StringBuilder(); while (decimal != 0) { result_3.insert(0, Integer.toHexString(decimal & 15)); decimal >>= 4; } System.out.println(result_3.insert(0, "0x").toString());
decimal = 55; StringBuilder result_4 = new StringBuilder(); int number = 15; while (true) { result_4.insert(0, Integer.toHexString(decimal & number).charAt(0)); if (number >= decimal) { break; } number <<= 4; } System.out.println(result_4.insert(0, "0x").toString());
|
- 二进制转换其他进制
折叠代码块JAVA
复制代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
|
int decimal = 55;
int binary = 0b110111;
int octal = 067;
int hex = 0x37;
int result_1 = 0; int times = 0; binary = 0b110111; while (binary != 0) { result_1 += (binary & 1) * Math.pow(2, times++); binary >>= 1; } System.out.println(result_1);
StringBuilder result_2 = new StringBuilder(); binary = 0b110111; while (binary != 0) { result_2.insert(0, String.valueOf(binary & 7)); binary >>= 3; } System.out.println(result_2.insert(0, "0").toString());
StringBuilder result_3 = new StringBuilder(); binary = 0b110111; while (binary != 0) { result_3.insert(0, String.valueOf(binary & 15)); binary >>= 4; } System.out.println(result_3.insert(0, "0x").toString());
|
或|
- 特点:
00101111 | 00001111(可以保留全部有效位,原来是1,肯定还是1)
- 可以用于一个数低四位与高四位数据取出后交换其位置。(或操作,原来是什么,现在还是什么)
折叠代码块JAVA
复制代码
1 2 3 4 5 6
| int number = 35; int high = number & 240; int low = number & 15; int newNumber = (high >> 4) | (low << 4); System.out.println(newNumber);
|
异或^
特点
6 ^3 ^ 3=6(异或两次还是原来的数据)
作用
- 可以用来
简单加密
- 用于不给其他变量,
交换两个数的数据(int加减可能会超出数据范围,用异或就不会超出范围)
左移<<
左移几位相当于乘几个2(后边二进制补0)
右移>>
右移几位相当于除以几个2,只保留整数(前边二进制正数补0,负数补1)
无符号右移 >>>
原来的前边都补0
赋值相关
折叠代码块JAVA
复制代码
1 2 3 4 5 6 7 8 9 10
| short s = 3;
s = (short)s + 3;
s += 3;
temp = 3; i = i + 1; i = temp
|
int i = 3; i = i++
字节码解释
流程语句
分号是一句代码的结束,if后边放了分号,if就不控制后边的代码块了
- java
一个大括号一个作用域。作用域外无法访问作用域内
折叠代码块JAVA
复制代码
1 2 3 4 5 6 7
| { a = 0; System.out.println(a); }
System.out.println(a);
|
- switch
- 无论default在最前边还是最后边(default位置可以随便放),都是
先判断case,最后判断default
- 判断的时候可以使用
字符串和枚举进行判断,但是case不能有与判断类型不一样的判断分支.
break在最后挨近大括号可以不用写.因为执行完就是最后一个大括号了
- if与switch比较
- switch效率相对高,因为直接把所有的情况都加载到内存,if还需每个区间分别执行,效率更低
- if更简单,数据量较少的时候用if更方便.switch写的较麻烦(switch支持枚举和字符串).
while和for的区别与共通
- 区别:while的循环变量定义在while前,while循环完之后,该变量还可以用.for循环结束,循环变量从内存销毁.
- 共通:while(true) for(;;)(中间默认true)都可以无限循环,可以在其他条件下控制循环.
- while和for的使用视情况而定
- 有些情况下需要无限循环,由用户或其他条件控制退出.
- for的其他写法
折叠代码块JAVA
复制代码
1 2 3 4 5 6 7 8 9
| for(System.out.println(1),System.out.println(1);System.out.println(1);System.out.println(1)){
}
for(int i = 0, j = 0; a<3 && b< 4; a++, b++) {
}
|
常用转义符号
折叠代码块YAML
复制代码
1 2 3 4
| \t(制表符): 以每个单元格进行对齐 \b(退格): 将\b后边的字符串或光标向前挪一个,覆盖原字符串 \r(按下回车键): \r后边的字符串或光标挪到本行开头,覆盖原字符串 - Windows回车是\r\n,Linux回车是\n
|
数组
特点
- 同一类型数据集合
- 是一种容器(是一个内存中的实体)
- 建立后需要明确长度.
初始化
折叠代码块JAVA
复制代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| String[] arr = new String[4];
String[] arr1 = {"1". "2"};
Car[][] arr2 = new Car[3][];
arr2[0] = new Car[13];
arr2[1] = new Car[]{1, 2, 3};
|
二维数组使用场景
- 数据多了用数组存,数组多了用二维数组存.
- 存数据表
其他
折叠代码块JAVA
复制代码
1 2 3 4
| int arr[] = new int[3]; int arr[][] = new int[3][]; int[] arr[]= new int[3][];
|
函数
函数也叫做方法,是类成员(不可以在函数中套函数)
public和static都是修饰符.public是权限修饰符, static是静态修饰符
- 函数体现了
封装性,是一个一个的功能
- void默认会写
return ;但是定义函数最好要有返回值.
- 函数
定义
- 思考
结果是什么(返回值类型);
- 思考
是否需要未知变量参与运算(参数列表).
- 函数在
内存加载过程(java Demo)
- 会
自动寻找Demo类中是否有main()函数.找到会从main()执行,找不到会报错
- 每个函数都是先进入stack执行,执行完,从stack删除.包括main()函数
- 注意:函数执行就是在不停的进行栈操作.
- 函数的
自我调用是递归。
方法重载(OverLoad)(可以参数个数不同,也可以参数类型不同,与返回值类型无关)
折叠代码块JAVA
复制代码
1 2 3 4
| public int my(int a){ } public int my(int a,int b){ } public int my(double a){ }
|
Java虚拟机
- Java是基于C++的优化,把
C++的指针变成了Java的引用
- JVM会在内存创建一片区域用来java程序运行
- 会分成不同的处理区域,每个区域运算方式不同
寄存器=>CPU调用
本地方法区=>系统相关,linux和windows等不同
方法区
栈内存:存局部变量(包括变量名),是在方法中定义的东西.变量作用域结束,变量销毁.
堆内存:存数组和对象(数组也是对象),new就建立在堆中
堆中数据会默认初始化值.
变量名赋null,相当于断了和对象的连接,堆中该对象会成为垃圾(失去了引用),被GC不定时自动回收,析构函数回收
- C++的垃圾回收需要程序员手动执行,否则会堆溢出.(使用~)
面向对象
new: 可以看作是开辟空间的运算符.
与面向过程比较
- 都是思想,只不过是不同的思考习惯.
- 面向过程:一个流程,
- 面向对象:某个东西有某功能(封装某功能),比面向过程更简洁
用面向对象写代码
- 先想所涉及的
对象都有什么,然后再去想其特性.后期就是如何维护各个对象之间的关系.
- 一般来说
名词都是对象.
- 用
属性和行为来描述类
行为属于哪个对象,看哪个对象更清楚这个行为
注意事项
- 一个文件只可以写一个public的类,其他的类不加public可以写到有public的文件中.
- 类中的方法可以传递类类型.
折叠代码块JAVA
复制代码
1
| public void doSth(Car c){}
|
成员变量和局部变量
- 成员变量定义在类中,在方法外,存在于heap中,有初值.
生命周期跟随类
- 局部变量定义在方法中,在方法内,存在于stack中,需要初始化后才能使用,
生命周期跟随方法
局部变量和成员变量同名 ,用近的那个
成员变量和构造方法
先初始化成员变量,然后调用构造方法
匿名对象
封装(Encapsulation)
作用
好处(可以参考电脑机箱)
封装原则
- 将不需要对外提供的内容都隐藏起来
- 将属性隐藏,提供公共方法来访问.(让数据更可控)
其他
私有可以看作封装的一种体现.
- 用
getter和setter可以更好的对数据进行限制(数据范围或者数据格式等),让数据更安全
变量私有化,行为公开化
- private在内存不能访问,是因为有
数字签名.
- 将数据设置为private,使用get和set来进行获取和赋予数据(让数据更可控)
折叠代码块JAVA
复制代码
1 2
| public int getAge(){} public void setAge(int age){}
|
构造函数(也可以叫构造器)
- 函数调用会进栈,构造函数也会进入
- 与类名相同,没有返回类型和返回值
- 默认调用无参构造函数.
- 如果重写构造函数,申请对象也想不传参,就需要同时定义一个无参构造方法.
- 构造函数可以写
return ;.
- 类是
pubic,构造函数默认是public
this
- 指向本对象,用于
变量的区分.和调用该对象的方法
折叠代码块JAVA
复制代码
1 2 3 4 5
| Person(String name){ name = name; } this.speak().
|
- this()的作用
调用本类无参构造方法,需要放到重载构造方法第一行.(初始化需要先执行,用this()提高了代码复用性)
- 每一个对象的函数进入栈的时候都会有一个默认的this指向所属对象.
static
- 用来修饰成员变量和方法
- 修饰的成员被所有对象共享
- static修饰的可以叫做
静态变量,类变量.不被static修饰的可以叫做实例变量,成员变量
- 静态方法中不能使用非静态的成员或方法,只能使用静态成员或方法(直接使用,可能方法还没有加载到方法区)
- 静态成员随着类加载存在,类销毁则消失.
- 方法如果只访问静态变量可以使用静态方法,如果访问非静态变量,就需要非静态方法
静态代码块可以用于类的初始化,一般是类中全是静态成员.
静态方法中没有this
继承
好处
- 提高了
代码复用性
- 类与类产生了关系,为多态提供了前提
支持单继承
- C++支持多继承
- Java没有多继承,是因为不同父类可能有相同的方法.可以多实现.
支持多重继承
继承体系
- 查看体系中的
顶层类,了解体系基本功能
- 创建体系最
子类对象,来实现更多功能
注意
- 想要子类不完全继承父类的所有方法,父类专有或不想其他类用,就用private
- 子类继承父类,先调用父类的构造方法(默认子类构造函数有super(),调用父类无参的).
- 子类中构造函数默认有super()是因为继承过来的某些成员属性可能需要初始化
- 子类不能重写父类构造函数,不能继承父类构造函数,
- 在同一个构造函数中,super和this只能用一个,如果两个都有,本构造对象和this()都会访问父类了
折叠代码块JAVA
复制代码
1 2 3 4 5 6 7
| class Zi extents Fu{ Zi(){ System.out.println(); } }
|
super
- 代表父类空间.(没有申请对象)
- 可以调用父类的构造函数,公有成员变量和公有方法,不能调用私有成员变量和方法.
重写(也叫覆盖,override)
- 子类方法需要和父类方法保持一致,修饰符级别可以大于等于父类.
- 静态只能覆盖静态函数
- 如果参数列表不同,就不是重写了.而是另一个方法.如下就不是重写:
折叠代码块JAVA
复制代码
1 2 3 4
| public int say(){}
public int say(int a){}
|
- 用途
- 用新的方法,而不修改原来的方法,扩展了程序,避免了危险.
- 弊端
- 可能重写底层方法,导致危险.(底层不需要修改的方法用final)
final
- 修饰过的方法在子类无法重写.无法重写只可以供每一个对象使用
折叠代码块JAVA
复制代码
1 2 3
| public static final int say(){
}
|
- 修饰过的类,子类无法继承
折叠代码块JAVA
复制代码
1 2 3
| public final class say{
}
|
- 修饰过的变量无法重新赋值.成为常量.因为不能变,所以加static,供所有对象用.特定名字,可读性更高
折叠代码块JAVA
复制代码
1 2 3 4
| static final int NUMBER = 11;
static final Element element = new Element();
|
抽象
含义
- 功能相同,但是功能的具体实现不同,可以将功能抽取出来
作用
样例
折叠代码块JAVA
复制代码
1 2 3 4 5 6 7 8 9 10
| public abstract class Person{ public abstract void say(); public void talk(){ System.out.println(1); } public void chat(Person person){ System.out.println(person.talk()); } }
|
特点
- 抽象类能够实例化吗?
- 不能实例化,抽象类只能是父类,由子类实现所有方法,实例化子类
- 抽象类如何用?
- 由继承类继承,重写所有方法.
- 继承抽象方法,扩充新的抽象方法
- 抽象类是否只有抽象方法?
- 有抽象方法,也可以有非抽象方法
- 都是非抽象方法(有方法体,没内容),却是抽象类,用于不让该类创建对象,AWT的适配器对象就是
- 抽象关键字可以修饰哪些东西?
- 修饰类:被继承
- 修饰成员方法:被重写
- 不能修饰成员变量:修饰了没有意义
- 抽象类有无构造方法?
- 抽象关键字不可以和那些关键字共存?
- static,加了static,该方法将属于类,但没有方法体,不能直接调用.
- private,抽象无法重写
- final,抽象需要重写
示例
折叠代码块JAVA
复制代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
|
abstract class CompanyEmployee{ private String name; private String id; private double pay; CompanyEmployee(String name, String id, double pay){ this.name = name; this.id = id; thid.pay = pay; } public abstract void work(); } class Manager extends CompanyEmployee{ private int bonus; Manager(String name, String id, double pay, int bonus){ super(name, id, pay); this.bonus = bonus; } public void work(){ System.out.println("code"); } } class Programmer extends CompanyEmployee{ Programmer(String name, String id, double pay){ super(name, id, pay); } public void work(){ System.out.println("manage"); } }
|
接口
用途
- 如果抽象类中的方法都是抽象的,可以用接口来表示
- 想要功能更具有扩展性,就要多使用接口.
特点
- 编译完之后也是class文件
- 只能被实现
- 接口成员都是公共的
- 不能实例化,可以由实现了接口的子类实例化
- 可以由类多实现:不同的接口有相同的方法,但没有方法体,所以避免了多继承的不确定性
- 接口之间可以继承,同时可以多继承(因为没有方法体)
深层理解
- 接口是对外暴露的规则(如何使用某功能)
- 接口是程序的功能扩展(一个接口可以做很多事情)
- 接口的出现降低了耦合性(两者之间的关联程度不需要太高就可以使用)(降低耦合性简称解耦)
- 定义接口,如果参数个数过于复杂,可以不定义参数列表,交给子类用成员变量解决。
常见成员
- 全局常量:
public static final(这三个修饰符哪个不写,默认会加上没有的)
- 抽象方法:
public abstract (两个修饰符不加,也会默认加上)
接口示例
折叠代码块JAVA
复制代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| interface Demo{ public static final String COMPANY = "Easul"; public abstract void talk(); public abstract void say(); } class DemoImpl implements Demo{ public void talk(){ } public void say(){ } } class Test{ public static void main(String[] args){ DemoImpl d = new DemoImpl(); d.talk(); DemoImpl.COMPANY; Demo.COMPANY; } }
|
接口代码理解
- BookPC相当于早就写好的一个类,里边可以实现由写好的接口进行的一系列操作.因为知道由接口返回的数据是什么,所以可以提前做好处理
- 接口是一个共性的东西,以后可能会有多种数据来源,所以不同数据来源只需要实现该接口,就相当于扩充了更多的数据来源.
折叠代码块JAVA
复制代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| interface USB{ public abstract void open(); public abstract void close(); } class BookPC{ public static void main(String[] args){ useUSB(new UPan()); } public static void useUSB(USB u){ u.open(); u.close(); } }
class UPan implements USB{ public void open(){ System.out.println("open"); } public void close(){ System.out.println("close"); } }
|
接口与抽象类的异同
- 相同
- 不同
- 抽象类定义某体系基本内容.
- 接口定义体系的额外功能.
多态
理解
- 相当于猫科动物有老虎,狮子,猫等
- 可以想成是多种形态.例如函数的重载可以看成多态,子父类中的同名参数可以看成多态.
- 对象的多态就是既有本类的形态,又有父类的形态.
- 对象多了,操作起来麻烦,所以可以用父类来统一操作.
好处
坏处
向上造型
向下造型
常见错误
折叠代码块JAVA
复制代码
1 2 3 4 5 6 7
| Animal a = new Animal(); Cat c = (Cat) a;
Animal a = new Dog(); Cat c = (Cat) a;
|
成员变量
折叠代码块JAVA
复制代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| class Fu{ int num = 3; } class Zi extends Fu{ int num = 4; }
class Test{ public static void main(String[] args){ Fu f = new Zi(); f.num; } }
|
成员函数
折叠代码块JAVA
复制代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| class Fu{ void show(){ System.out.println(1); } } class Zi extends Fu{ void show(){ System.out.println(12); } } class Test{ public static void main(String[] args){ Fu f = new Zi(); f.show(); } }
|
静态函数
折叠代码块JAVA
复制代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| class Fu{ static void show(){ System.out.println(1); } } class Zi extends Fu{ static void show(){ System.out.println(12); } } class Test{ public static void main(String[] args){ Fu f = new Zi(); f.show(); } }
|
自始自终都是子类对象在进行转换
折叠代码块JAVA
复制代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| abstract class Animal{ public abstract void eat(); } class Dog extends Animal{ public void eat(){ } } class Pig extends Animal{ public void eat(){ } } class Test{ public static void main(String[] args){ method(new Dog()); method(new Pig()); } public static void method(Animal animal){ animal.eat(); } }
|
native
修饰本地方法,最后会调用底层C的方法
内部类
特点
- 内部类可以直接访问外部类所有成员
- 外部类访问内部类,需要创建内部类的对象
- 相当于一种封装
- 可以被修饰符修饰
- 内部类方法重写的时候权限不能小于外部类
- 静态只能覆盖静态函数
用途
分析事物的时候,事物内部还有事物,且内部事务需要访问外部事物的成员.
成员内部类
相当于类的一个普通成员
折叠代码块JAVA
复制代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| public class Test { public static void main(String[] args) { MySame.InnerClass e = new MySame().new InnerClass(); e.say(); MySame.InnerClass e1 = new MySame().createInner(); e1.say(); } }
public class MySame { private int number = 1; public InnerClass inner = null;
public InnerClass createInner() { if (inner == null) inner = new InnerClass(); return inner; }
public void method() { if (inner == null) inner = new InnerClass(); inner.say(); }
public class InnerClass { public void say() { System.out.println(number); } } }
|
静态内部类
特点
- 相当于类的一个静态成员
- 外部类一加载,内部类会同时加载,可以直接调用.相当于一个外部类
- 内部类是静态的,外部类成员是静态的,那么可以用内部类的静态方法直接访问外部类成员,不用申请对象.
- 内部类方法是静态,内部类也需要是静态,不然内部类方法无法加载.
示例一
折叠代码块JAVA
复制代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| public class Test { public static void main(String[] args) { MySame.InnerClass e = new MySame.InnerClass(); e.talk(); MySame.InnerClass e1 = new MySame().createInner(); e1.talk(); MySame.InnerClass.say(); } }
public class MySame { private static int num = 3; public InnerClass inner = null;
public InnerClass createInner() { if (inner == null) inner = new InnerClass(); return inner; }
public static class InnerClass { public void talk() { System.out.println(2); }
public static void say() { System.out.println(num); } } }
|
示例二
折叠代码块JAVA
复制代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| class Outer{ int num = 3; class Inner{ int num = 4; void show(){ int num = 5; System.out.println(num); System.out.println(this.num); System.out.println(Outer.this.num); } } void method(){ new Inner().show(); } } class Test{ public static void main(String[] args){ new Outer().method(); } }
|
局部内部类
在方法中写一个类(个人感觉是想要在方法中嵌套其他方法采用的,java不能在方法中套方法)
方法中的内部类访问局部变量,局部变量需要声明为final类型.因为方法进栈,局部变量进栈,方法出栈,局部变量出栈,show()方法中用的x可能就没有了,所以用final,把x变成常量,然后show()方法中的数就是固定的9.
折叠代码块JAVA
复制代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| class Outer{ Object method(final int y){ final int x = 9; class Inner{ void show(){ System.out.println(x); System.out.println(y); } } Object in = new Inner(); return in; } } class Test{ public static void main(String[] args){ object obj = new Outer().method(19); } }
|
匿名内部类
特点
- 必须继承或实现一个外部类或接口.(new Chat()就是在实现一个接口)
- 可以理解为创建了子类对象.
使用场景
- 函数的参数是接口类型,且接口中的方法不超过3个.用匿名内部类作为参数传递.
示例
折叠代码块JAVA
复制代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| interface Chat{ public abstract void English(); }
Chat c = new Chat(){ public void English() { System.out.println(); } }; c.English();
new Chat(){ public void English() { System.out.println(); } }.English();
public class MySame{ public void show(Chat c){
} } public class Test { public static void main(String[] args) { MySame e = new MySame(); e.show(new Chat(){ public void English() { System.out.println(); } }); } }
|
Object类
含义
常用方法
折叠代码块YAML
复制代码
1 2 3 4 5 6
| equals(Object): 默认判断两个引用是否指向同一对象.重写时一般需要重写hashCode方法 - p1 == p2两个对象比较的是地址值 hashCode(): 默认得到对象的十进制存储地址.可以重写该方法赋予每一个对象自定义唯一标识 - 同一个对象需要有同样的hashCode() Class<> getClass(): 得到运行对象的字节码文件对象 toString(): 默认获取类名(getClass().getName()获取)@十六进制hashCode值(hashCode()获取)
|
折叠代码块JAVA
复制代码
1 2 3
| Student s = new Student();
System.out.println(s);
|
equals()重写示例
折叠代码块JAVA
复制代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
| class Test{ public static void main(String[] args){ System.out.println(new Person(20).equals(new Person(20))); } } class Person{ private int age; Person(int age){ this.age = age; } public boolean equals(Object obj){ if(!(obj instanceof Person)){ throw new ClassCastException("类型错误"); } Person p = (Person)obj; return this.age == p.age; } }
public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Element element = (Element) o; if(FIRST_NUMBER != element.FIRST_NUMBER) return false; if(getName() == null){ if(element.getName()!=null){ return false; } } else if(!getName.equals(element.getName)){ return false; } return true; }
|
getClass()
用于获取的字节码文件对象
每一个字节码文件加载到方法区之后,会自动为其在堆创建一个Class类的对象(字节码文件对象),下边为它的构造
折叠代码块JAVA
复制代码
1 2 3 4 5 6 7 8 9 10
| class Class{ name field constructor method }
|
后期创建对象,就根据这个字节码文件对象创建新的对象
折叠代码块JAVA
复制代码
1 2 3 4 5 6 7 8 9 10 11 12
| class Test{ public static void main(String[] args){ Person p1 = new Person(1, "E"); Person p2 = new Person(2, "W"); Class<? extends Person> c1 = p1.getClass(); Class<? extends Person> c2 = p2.getClass(); System.out.println(c1 == c2); System.out.println(c1.getName()); } }
|
![image]()
包
作用
- 就是个文件夹,在文件第一行
- 给类文件分类管理
- 可以给类提供多层命名空间
- 也是一种封装形式
定义
package mypackage,包名称小写。定义自己的包初始位置。
运行
mypackage.Demo,运行需要加入包名,且类需要放到mypackage文件夹下
- 导入别人的类库,需要放到顶层目录,否则会编译出错。
导包(导入的是包中的类,不导入包中的包)
- 不用写包名,可以直接使用类。
- 导入的位置是从当前顶层包所在的位置算起。
import test.*;导入test文件夹中所有类,不包括子包的类。
示例
折叠代码块
复制代码
1 2 3 4 5 6 7 8 9
| test ├── bin └── test ├── mypackage │ └── Demo.java ├── demoa │ └── DemoA.java └── demob └── DemoB.java
|
折叠代码块JAVA
复制代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| package test.mypackage; import test.demoa.DemoA; import test.demob.DemoB; class Demo{ public static void main(String[] args){ DemoA d = new DemoA(); d.show(); System.out.println(1); } }
package test.demoa; import test.demob.DemoB; public class DemoA extends DemoB{ public void show(){ System.out.println("asdf"); method(); } }
package test.demob; public class DemoB{ protected void method(){ System.out.println("asdfgh"); } }
|
进入到test文件夹,然后执行下边的命令
折叠代码块BASH
复制代码
1 2 3 4 5 6
|
javac -d ./bin/ ./test/**/*.java cd bin
java test.mypackage.Demo
|
Jar
含义
- java的压缩包,可以把多个包合并成一个包
- 是一个命令行工具
用法
折叠代码块BASH
复制代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
|
jar -cvf mytest.jar test
jar -tvf mytest.jar test
jar -xvf mytest.jar test
export CLASSPATH=./mytest.jar:$CLASSPATH
java test.mypackage.Demo
|
异常
含义
- 运行时期发生的不正常情况
- 放到非法情况下抛出,可读性和可维护性更强.
- 将问题封装成对象,通过抛出,告诉调用者.(分开了正常流程代码和异常处理代码)
- 不同的问题用不同的类描述
- 可能出现问题,就抛出异常。
抛出信息组成
- 异常所在的线程名称,异常名称,异常信息,异常位置。
体系
- Throwable(它和其子类才具有可抛性)
- 可处理的(Exception类)
折叠代码块YAML
复制代码
1 2
| 编译时不检测异常: RuntimeException(正常运行时异常)及其子类,问题的发生更多由调用者或内部状态改变导致 编译时被检测异常: Exception和子类都是(RuntimeException体系除外),需要在编译时就处理该问题
|
- 不可处理的(Error类,由JVM抛出的严重问题)
折叠代码块YAML
复制代码
1 2
| NoClassDefFoundError: (未找到调用类错误) OutOfMemoryError: (内存溢出错误)
|
- 通过
throws(在函数上声明可能的异常类)和throw(抛出异常对象)来体现抛出
- 子类后缀名都用父类名做后缀,提高了阅读性
理解
- 异常类如果继承了
Exception类,发生了异常,可以处理,catch;处理不了,throws抛出,编译时检查
- 异常类如果继承了
RuntimeException类,发生了异常,不需要throws,也可以throws或catch,编译时不检查
异常的执行流程
折叠代码块JAVA
复制代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
|
class Test{ public static void main(String[] args){ int[] arr = new int[3]; Demo d = new Demo(); d.method(arr, 3); } } class Demo{ public void method(int[] arr, int index){ System.out.println(arr[index]); } }
|
定义抛出异常
折叠代码块JAVA
复制代码
1 2 3 4 5 6 7 8 9 10 11 12
| class Demo{ public int method(int[] arr, int index){ if(arr == null) throw new NullPointerException("数组引用不能为空"); } if(index >= arr.length){ throw new ArrayIndexOutOfBoundsException("数组的角标越界:" + index); } return -1; } }
|
自定义异常类
折叠代码块JAVA
复制代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102
|
class MinusIndexException extends Exception{ MinusIndexException(){ } MinusIndexException(String msg){ super(msg); } } class Demo{ public int method(int[] arr, int index) throws MinusIndexException{ if(index < 0){ throw new MinusIndexException(); } return array[index]; } } class Test{ public static void main(String[] args) throws MinusIndexException{ int[] arr = new int[3]; Demo d = new Demo(); d.method(arr, -3); } }
class MinusIndexException extends RuntimeException{ MinusIndexException(){ } MinusIndexException(String msg){ super(msg); } } class Demo{ public int method(int[] arr, int index){ if(index < 0){ throw new MinusIndexException(); } return array[index]; } } class Test{ public static void main(String[] args){ int[] arr = new int[3]; Demo d = new Demo(); d.method(arr, -3); } }
class MinusIndexException extends Exception{ MinusIndexException(){ } } class Demo{ public int method(int[] arr, int index) throws MinusIndexException, NullPointerException{ if(index == null){ throw new NullPointerException(); } if(index < 0){ throw new MinusIndexException(); } return arr[index]; } } class Test{ public static void main(String[] args){ try{ int[] arr = new int[3]; Demo d = new Demo(); d.method(arr, -3); } catch(MinusIndexException e){ System.out.println(e.getMessage()); System.out.println(e);/ e.printStackTrace(); System.out.println("负数角标异常"); } catch(NullPointerException e){ System.out.println(e.toString()); } catch(Exception e){ System.out.println(e.getMessage()); } finally{ System.out.println("finally"); } System.out.println(11); } }
|
finally的作用
try catch finally的组合
- try catch finally
- try catch:用于没有资源需要释放的情况
- try finally:(常用)用于异常无法catch,但需要关闭资源(需要throws)
Java编译器检查过程
- 检查是前边检查完才检查后边
- 检查语法错误=>>检查编译错误(异常等)
异常处理
- 真实开发异常输出到log日志
- 异常执行,会阻断剩下的所有代码执行
异常的注意事项
- 子类在覆盖父类方法时,父类的方法如果抛出了异常,子类的方法只能抛出父类的异常或该异常的子类(也可以不抛)
折叠代码块JAVA
复制代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| class AException extends Exception{ } class BException extends AException{ } class CException extends Exception{ } class Fu{ void show() throws AException{ } } class Zi extends Fu{ void show() throws BException{ } }
|
- 如果子类抛出的是父类没有的异常,那么会出问题
折叠代码块JAVA
复制代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| class AException extends Exception{ } class BException extends AException{ } class CException extends Exception{ } class Fu{ void show() throws AException{ } } class Zi extends Fu{ void show() throws CException{ } } class Test{ public static void main(String[] args){ methos(new Fu()); methos(new Zi()); } public static void method(Fu f){ f.show(); } }
|
- 父类抛出多个异常,子类只能抛出父类子集。
- 如果父类的方法没有抛出异常,子类也不能抛出异常,只能try
折叠代码块JAVA
复制代码
1 2 3 4 5 6 7 8 9
| interface Inter{ void function(); } class D implements Inter{ void function(){ } }
|
异常+面向对象的分析
- 异常转换(异常封装):接收到一个异常,但是抛出了上级更能明白和解决的异常
- 关于“毕老师用电脑上课”进行分析,有两个对象,一个是老师,一个是电脑,老师使用电脑
- 电脑可以运行(run()),可以重启(reset()),老师有名字(name),有电脑(computer),可以讲课(prelect())(方法和谁关联性更大就给谁)
- 老师讲课的时候(prelect()),需要让电脑打开,然后讲课。
- 在讲课过程中电脑可能出现问题:蓝屏,冒烟(用异常类封装状态),因为是电脑的问题,所以给电脑定义state记录电脑状态值,然后运行时(run())根据状态值判断电脑运行时是否出现问题。出现问题就创建异常对象并抛出。
- 老师讲课的时候(prelect())可能电脑会出现问题,相关代码使用try运行, 出现问题,用catch来接。
- 蓝屏,重启电脑即可,调用电脑的重启方法(reset()),然后继续讲课
- 电脑冒烟,自己无法处理,老师布置自我练习的任务(test()),然后将问题上抛。使用异常转换,告诉上级可以看得懂的信息
- 公司需要毕老师进行讲课,创建毕老师这个对象,然后调用讲课方法(perlect()),但是讲课可能出问题,所以需要接收并处理异常信息,例如让另一个老师讲
折叠代码块JAVA
复制代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73
| class Computer{ private int state = 2; public void run() throws LanPingException,MaoYanException{ if(state == 1) throw new LanPingException("电脑蓝屏"); else if(state == 2) throw new MaoYanException("电脑冒烟"); System.out.println("电脑运行"); } public void reset(){ state = 0; } } class Teacher{ private String name; private Computer computer; Teacher(String name){ this.name = name; computer = new Computer(); } public void prelect() throws NoPlanException{ try{ computer.run(); System.out.println("讲课"); } catch(MaoYanException e){ System.out.println(e); test(); throw new NoPlanException("课时进度无法完成"+e.getMessage()); } catch(LanPingException e){ System.out.println(e); computer.reset(); System.out.println("电脑重启"); prelect(); } } public void test(){ System.out.println("学生练习"); } } class Company{ public static void main(String[] args){ Teacher t = new Teacher("毕老师"); try{ t.prelect(); } catch(NoPlanException e){ System.out.println(e); System.out.println("换人"); Teacher t = new Teacher("Easul"); } } } class LanPingException extends Exception{ LanPingException(String msg){ super(msg); } } class MaoYanException extends Exception{ MaoYanException(String msg){ super(msg); } } class NoPlanException extends Exception{ NoPlanException(String msg){ super(msg); } }
|
类
- 类的销毁随着jvm的销毁而产生.
- 如果加载的类过多,GC可以对类进行回收(类也是一种对象),长时间不用的就回收.
- 类的一般初始化过程:默认初始化(成员变量加载到内存,赋值0等默认值)==>显式初始化(成员变量赋值后边等号给的值)==>构造初始化(构造函数初始化)
权限修饰符
![image]()
instanceof
用途
- 判断对象的具体类型,只能判断引用类型(一般用于强转前,防止强转失败,增强代码健壮性)
示例
折叠代码块JAVA
复制代码
1 2 3 4 5 6 7 8 9
| public void method(Animal a){ if(a instanceof Cat){ Cat c = (Cat) a; c.catchMouse(); } else if(a instanceof Dog){ Dog d = (Dog) a; d.woof(); } }
|
工具类
- 一个非静态方法都没有,通常是工具类,只有静态方法.
- 不需要创建对象,可以将构造函数私有化.创建对象反而消耗内存.
设计模式
对问题行之有效的解决方式
单例设计模式
- 保证一个类在内存中只有一个对象,防止不停创建对象消耗资源
- 可用于配置信息的修改(公有动态信息)
实现方式:
- 私有化构造函数
- 创建好本类实例
- 提供一个方法获取本类实例
相关代码
饿汉式用的多,懒汉式在多线程可能保证不了对象唯一性,但懒汉面试用的多
折叠代码块JAVA
复制代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
|
public class Tool{ private static Tool tool = new Tool(); private Tool(){ } public static Tool getInstance(){ return tool; } }
public class Tool{ private static Tool tool = null; private Tool(){ } public static Tool getInstance(){ if(tool == null) tool = new Tool(); return tool; } }
|
单例解释
- main()函数和其所属类进入方法区,然后main()进栈
- 使用Single类,构造方法进非静态方法区,变量s和getInstance()进入静态方法区.s默认值为null
- 在堆中创建Single对象,然后将地址赋给s
- 在main()中,访问getInstance()方法,它进栈,
- 返回对象的地址,之后弹栈,地址赋给s1,s2也进行相同的操作
![image]()
主函数的解释
JVM只调用和固定格式一样的主入口
折叠代码块JAVA
复制代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
|
class test{ public static void main(String[] args){ } public static void main(int x){ } }
|
堆, 栈, 方法区的存储
- 栈:普通变量, 调用的方法
- 堆:对象,对象中的成员变量
- 方法区:类, 方法, 静态成员
- 静态区:静态变量, 静态方法,
- 非静态区:成员方法,构造方法
代码块
局部代码块
可以定义局部变量的生命周期,这个变量不用的时候就可以自动从内存中删除掉
折叠代码块JAVA
复制代码
1 2 3 4 5 6 7
| public void say(){ { int number = 1; } System.out.println(number); }
|
构造代码块
用于给所有对象初始化相同的数据,构造函数是给不同对象初始化特有数据
折叠代码块JAVA
复制代码
1 2 3 4 5
| private double age = 1; { System.out.println(age); }
|
静态代码块
折叠代码块JAVA
复制代码
1 2 3 4
| static{ System.out.println(1); }
|
各种成员加载顺序
Java类编译
- Java编译一个带有main()入口的class,如果发现在这个class中需要的某个类没有,那么就会在classpath进行查找,查找不到就会继续找同名的java文件,然后编译该文件.
- 也可以直接使用
javac *.java(同时编译某目录所有文件)
三种引用类型
数组类型,类类型,接口
内存分配相关
数据初始化的内存分配
- stack(栈),分配快,小
- heap(堆),分配慢,大
- 对于
int[] arr = new int[3],arr存到栈,也就是存一个变量,实际数组存到堆,
- new的数据在堆里生成之后,会有一个地址,栈里的变量指向这个地址.数据生成后根据数据类型赋了默认值.
- 栈里的数据只是起指向,没有默认值.
int x = 0,变量和0都存到栈里,因为没有new.使用包装类就存到堆里了
![image]()
二维数组在内存的分配
int[][] arr = new int[3][2];
- 先创建第一维,第一维排列在一块,默认指针为null
- 然后创建每一个二维,创建好了之后,将每一个二维的首地址赋给一维的那个地址.
- 因此可以对应二维数组第二维可以先不创建的情况
![image]()
![image]()
折叠代码块JAVA
复制代码
1 2 3 4 5 6 7
| int[][] arr = new int[3][]
System.out.println(arr);
System.out.println(arr[0]);
System.out.println(arr[0][0]);
|
构造函数在内存中的运行
- 先在stack加载main(),然后创建p2,相应的对象创建到堆里
- 给对象创建相应的成员变量,并赋予初始值
- 构造方法进栈,给n和a赋值,没有相应的变量,于是调用默认的this(),找到自己所属对象,为变量赋值.
- 赋值后弹栈,将对象地址赋值给p2
![image]()
对象的初始化在内存的分配
- 运行StaticDemo2这个类,那么先将类加载到方法区(方法区左边是非静态区,右边是静态区)
- 先将静态方法main()加载到静态方法区,然后将构造方法StaticDemo2(){}加载到非静态方法区.
- main()方法入栈,开始一句一句执行.
- 执行第一句,加载Person类到方法区,也就是加载Person类中的构造方法Person(String name, int age),show()方法到Person类的非静态方法区,country, method()到静态方法区.
- 调用method()方法,将方法从方法区入栈,从方法区找到并输出country,然后method()弹栈
- 执行第二句,变量p入栈,堆中创建Person的对象,并创建成员变量age, name,然后赋初值
- Person的构造函数入栈,传入参数,然后由this指向,将参数赋值给堆中的对象中的成员变量.
- 赋值完之后构造函数弹栈,Person对象的地址赋给p
- 执行第三句,调用show()方法,输出country, name, age,则从栈->堆->方法区的顺序依次找到变量输出
- 调用完弹栈.
- main函数执行完弹栈.
![image]()
静态成员的使用在内存的分配
静态成员特点
- 静态方法不能使用非静态方法是因为非静态的在堆中,静态的在方法区中,没有申请对象就无法调用该方法.
- 静态成员先于对象产生
- 静态成员属于类,
- 静态成员可以让对象共用,新的修改会覆盖掉旧的数据.
内存分配解析
折叠代码块JAVA
复制代码
1 2 3 4
| public class Animal{ public static int age; } System.out.println(Animal.age);
|
- 当运行Animal.age时,先加载Animal.class到方法区
- 在方法区开辟一块属于Animal.class的空间(静态区域),存放类中静态的变量或方法
![image]()
super在内存的分配
- ExtendsDemo2.class,main()函数加载到方法区,然后main()进栈,执行第一句
- 执行的时候,将Fu类和相应的构造方法加载到方法区,然后加载Zi类和相应的构造方法,普通方法.Zi类的super指向父类空间
- 在栈中创建变量z,在堆中创建对象Zi,然后分两块区域,一块是Fu的,一块是Zi的
- 将Fu的成员变量加载到Fu在堆的区域,然后将Zi的成员变量加载到Zi在堆的区域.(Fu类没有申请对象,所以在堆和方法区只放了父类空间)
- 对象创建完成,将地址赋给z
- 执行第二句代码,show()方法进栈,this找到Zi的num和super找到Fu的num输出,然后函数弹栈
- 最后main()弹栈
![image]()
子类调用父类更详细的内存解释
折叠代码块JAVA
复制代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| class Father{ int number = 4; { System.out.println("first"+number); } Father(){ show(); return ; } void show(){ System.out.println("F>>"); } } class Son extends Father{ int number = 4; { System.out.println("second"+number); } Son(){ super(); System.out.println("middle"); return ; } void show(){ System.out.println("s>>"+number); } } class test{ public static void main(String[] args){ Son s = new Son(); s.show(); } }
|
- ExtendsDemo5.class和main()方法加载到方法区,main()进栈并执行
- 创建Zi类对象,先将Fu类和其构造函数,普通函数加载到方法区,然后再加载子类的构造函数和普通函数加载到方法区.
- 在栈中创建变量z,在堆中创建对象,并将Zi的成员变量加载到堆(这个时候只加载了变量,并没有初始化)
- 调用Zi类的构造函数中的super(),先初始化父类.
- Fu()类进栈,调用show()方法,此时Fu()指向this当前对象,所以会先找Zi在方法区的该方法,然后在Zi的堆空间中找num,输出相应结果.这个时候因为子类成员变量只加载,还没有初始化,所以num为0
- 执行完super()后,开始先将Zi成员变量初始化,然后继续执行Zi构造函数中接下来的语句.这个时候num成为8
- Zi构造函数执行完成,对象创建完成,将地址赋值给z,然后执行z.show()
![image]()
重载内存图
调用show()方法的时候,会默认先从子类找,如果子类没有,通过super指向父类空间,再从父类空间找.
![image]()
一些小算法
- 累加算法:对一个元素进行规律性操作并记录下来.
- 计数器思想:对满足的某一条件进行计数
- 大圈套小圈:一种重复情况中的每一次都对应多种情况.
排序算法
冒泡排序
每一个和下一个比,留下了最后一个(bubbleSort)
折叠代码块JAVA
复制代码
1 2 3 4 5 6 7 8 9
| for(int i = 0; i < 5 - 1; i++){ for(int j = 0; j < 5 -1-i; j++){ if(arr[j] > arr[j+1]){ int temp = arr[j]; arr[j] = arr[j+1]; arr[j+1] = temp; } } }
|
选择排序
第一个不动,依次和后边的比较(selectSort)
折叠代码块JAVA
复制代码
1 2 3 4 5 6 7 8 9
| for(int i = 0; i < 5 - 1; i++){ for(int j = i+1; j < 5; j++){ if(arr[i] > arr[j]){ int temp = arr[i]; arr[i] = arr[j]; arr[j] = temp; } } }
|
算法优化:这里每次都交换,可以保存下标,只交换最后一次(最后找到最小的数,然后交换即可,)
折叠代码块JAVA
复制代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| for(int i = 0; i < 5 - 1; i++){ int index = i; int temp; for(int j = i+1; j < 5; j++){ if(arr[index] > arr[j]){ index = j; } } if(index != i){ temp = arr[index]; arr[index] = arr[i]; arr[i] = temp; } }
|
注意:Java中给函数传递数组时传递的是引用,那么就可以直接在函数中交换数组数据即可完成数组元素的交换.不需要返回数组.(堆中的数据已经进行了交换)
插入排序
希尔排序
快速排序
归并排序
堆排序
查找算法
顺序查找(用于无序)
折叠代码块JAVA
复制代码
1 2 3 4 5 6 7 8
| public static int getIndex(int[] arr, int number){ for(int i = 0; i < arr.length; i++){ if(arr[i] == number) return i; } return -1; }
|
折半查找(用于有序):
特点:大索引小于小索引就说明判断结束了
折叠代码块JAVA
复制代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| public static int halfIndex(int[] arr, int number){ int max = arr.length - 1; int min = 0; int mid = (max + min) / 2; while(arr[mid] != number){ if(arr[mid] > number) max = mid - 1; else min = mid + 1; if(max < min) return -1; } return mid; }
public static int halfIndex(int[] arr, int number){ int max = arr.length - 1; int min = 0; while(max < min){ int mid = (max + min) >> 1; if(arr[mid] > number) max = mid - 1; else if(arr[mid] < number) min = mid + 1; else return mid; } return -1; }
|
分块查找
v1.5.2