目录
- 常用的DOS命令
- 标识符的四大命名规则
- 标识符的使用规范
- java中的关键字/保留字
- IDEA快捷键
- 变量的分类和作用域
- 常量
- 变量和常量名规范
- 二元运算符的运算规则
- 字符串连接符
- 运算符的优先级
- 数据类型的转化
- 测试键盘输入:Scanner用法
- Math类的使用
- 方法
- 方法的重载
- 构成方法重载的条件
- 递归结构
- 面向对象编程(OOP)
- 堆、栈、方法区
- 构造方法(构造器 construtor)
- 构造方法的重载
- JAVA虚拟机内存模型概念
- 参数传值机制
- 垃圾回收机制(Garbage Collection)
- 垃圾回收相关算法
- 通用的分代垃圾回收机制
- 内存泄露
- this关键字
- this的用法
- static关键字
- 静态初始化块
- 包机制(package、import)
- 静态导入
- 继承
- 封装
- 多态
- 对象的转型
- 抽象类和接口
- 字符串String类详解
- java的API文档
- 内部类
- 数组
- 多维数组
- Comparable接口
B站视频链接: link
常用的DOS命令
标识符的四大命名规则
- 以字母、下划线_、美元符号$开头
- 其他部分可以是字母、下划线_、美元符号$和数字的任意组合
- 大小写有着各自的规范,长度没有限制
- 不可以是java的关键字
标识符的使用规范
- 表示类名的标识符:每个单词的首字母大写,如Man,GoodMan
- 表示方法和变量的标识符:第一个单词小写,从第二个单词开始首字母大写,称之为“驼峰原则”,如eat(),eatFood()
Java不采用ASCII字符集,而采用Unicode字符集。
java中的关键字/保留字
abstract | assert | boolean | break | byte | case |
---|---|---|---|---|---|
catch | char | class | const | continue | default |
do | double | else | extends | final | finally |
float | for | goto | if | implements | import |
instanceof | int | interface | long | native | new |
null | package | private | protected | public | return |
short | static | strictfp | super | switch | synchronized |
this | throw | throws | transient | try | void |
volatile | while |
变量是空间,变量名是空间的名称,数据是空间中储存的东西,我们通过变量名来操作变量。
java是强类型语言,即强制类型定义的语言,每一个变量都要定义其数据类型,一旦定义必须通过强制类型转换才能改变其数据类型,弱类型语言的数据类型可以通过不同的环境而改变,不用通过强制转换。
IDEA快捷键
主函数:psvm
输出:sout
看类的源码:ctrl+左键
自动生成构造器、get、set方法、equals等:alt+insert
查看错误:alt+enter
变量的分类和作用域
类型 | 声明位置 | 从属于 | 生命周期(作用域) |
---|---|---|---|
局部变量 | 方法或语句块内部 | 方法/语句块 | 从声明位置开始,直到方法或语句块执行完毕,局部变量消失 |
成员变量(实例变量) | 类内部,方法外部 | 对象 | 对象创建,成员变量也跟着创建。成员消失,成员变量也跟着消失 |
静态变量(类变量) | 类内部,static修饰 | 类 | 类被加载,静态变量就有效,类被卸载,静态变量就消失 |
数据类型 | 初始值 |
---|---|
int | 0 |
double | 0.0 |
char | ‘\u0000’ |
boolean | false |
常量
在java语言中,用关键字final定义常量,常量一旦被初始化后就不能再改。
-
声明格式:
final type varName=value;
常量命名通常用大写字母,单词之间用下划线隔开
1、2、3、’a‘、’b‘这些叫做字符常量,用final修饰的常量叫做符号常量。
变量和常量名规范
- 所有变量、方法都要见名知义
- 变量:首字母小写,遵循驼峰规则
- 常量:大写字母和下划线,MAX_VALUE
- 类名:首字母大写和驼峰原则
- 方法名:首字母小写和驼峰原则
整数型数据字节数:1、2、4、8
浮点型:4、8
字符型:4
布尔型:1或4
引用数据类型(4个字节):
- 类class
- 接口interface
- 数组array
浮点常量默认类型是double,要转为float数据后面需要加f
3.14E2:科学计数法,等于314
java中string不是一个类型,而是一个类
二元运算符的运算规则
- 整数运算
- 如果两个操作数里有一个为long,那么结果就为long
- 没有long,结果就是int,即使有short和byte数据
- 浮点运算
- 有一个double,结果就为double
- 只有全为float,结果才为float
- 取模运算
- 结果的符号和取余符号左边的操作数相同,如7%-3=1
- 结果的符号和取余符号左边的操作数相同,如7%-3=1
字符串连接符
“+”运算苻两侧的操作数中只要有一个是字符串(String)类型,系统就会自动将另一个操作数转换为字符串然后再进行连接,其他的都是加号的意思。
运算符的优先级
数据类型的转化
-
自动类型转换
-
强制类型转换
type(var)
测试键盘输入:Scanner用法
导入包:
import java.util.Scanner
Math类的使用
Math.random()该方法用于产生0到1区间的double类型的随机数,但是不包括1。
方法
用来完成某种特定功能的代码片段,类似于函数。
用于定义该类或该类的实例的行为特征和功能实现。
面向对象中,最基本的单位是类。
方法中的变量只能用于自己,外部不能使用。
方法的重载
重载指完全不同的,参数列表不一样的只是名称相同的方法。
构成方法重载的条件
- 形参类型、形参列表和形参顺序不同
- 只有返回值不同不构成方法的重载
- 只有形参的名称不同,不构成方法的重载
递归结构
很常见的算法,比如DFS,自己调用自己
包括两个部分,定义递归头和递归体。
递归头解决什么时候不调用自身方法,递归体解决什么时候需要调用自身方法。
面向对象编程(OOP)
面向过程重点关注如何执行,面向对象更倾向于设计。
对象是类的实例。
一个java文件可以同时定义多个class
类有三种成员:属性field、方法methon和构造器constructor
属性用于定义该类或该类对象包含的数据或者说静态特征,方法用于定义该类或者该类实例的行为特征和功能实现。
堆、栈、方法区
类的信息放在方法区,包括方法代码和常量池,方法区中的常量池中存放类中的常量,还有static属性和方法。
当开始执行main方法时,栈中就会有一个main方法的栈帧,其中存放main方法中的变量,只要执行方法就会开辟一个方法的栈帧。
构造的对象放在栈区里,与方法区不同的是,栈区内的对象更加具体,方法区是代码。
构造方法(构造器 construtor)
构造器用于对象的初始化,而不是创建对象
4个要点:
- 构造器通过new关键字调用
- 构造器虽然有返回值,但是不能定义返回值类型
- 如果没有定义构造器,编译器会自动定义一个无参的构造方法
- 构造器的方法名必须和类名一致
构造方法的重载
与普通方法的重载一样,改变参数,不过没有方法类型,不返回任何值。
JAVA虚拟机内存模型概念
栈
- 栈描述的是方法执行的内存模型,每个方法被调用都会创建一个栈帧(存储局部变量,操作数,方法出口等)
- JVM为每个线程创建一个栈,用于存放该线程执行方法的信息(实际参数、局部变量等)
- 栈属于线程私有,不能实现线程间的共享
- 栈的存储特性是”先进后出,后进先出“
- 栈是由系统自动分配,速度快,它是一个连续的内存空间
堆
- 堆用于存储创建好的对象和数组,数组也是对象
- JVM只有一个堆,被所有线程共享
- 堆是一个不连续的内存空间,分配灵活,速度慢
- 堆被所有的线程所共享,在堆上的区域,会被垃圾回收器作进一步划分,如新生代、老年代的划分
方法区(特性也是堆)
- 方法区是JAVA虚拟机规范,可以有不同的实现
- JDK7以前以“永久代”的方式做方法区
- JDK7部分去除“永久代”,静态变量、字符串常量池都挪到了堆内存中
- JDK8是“元数据空间”和堆结合起来
- JVM只有一个方法区,被所有线程共享
- 方法区实际也是堆,只是用于存储类、常量相关的信息
- 用来存放程序中永远不变或唯一的内容
- 常量池主要存放常量,如文本字符串,final常量值
参数传值机制
java中,方法的所有参数都是“值传递”,如果是基本数据类型参数的传值,副本不会影响原件,如果是引用类型参数的传值,引用类型指的是“对象的地址”,副本和原参数都指向同一个地址,改变副本指向地址对象的值,原件的也会改变。
垃圾回收机制(Garbage Collection)
内存管理
java的内存管理很大程度上就是:堆中对象的管理,其中包括对象空间的分配和释放
对象空间的分配:使用new关键字创建对象即可
对象空间的释放:将对象赋值null即可
垃圾回收过程
- 发现无用的对象
- 回收无用对象占用的内存空间
无用的对象指的就是没有任何变量引用该对象。java的垃圾回收器通过相关算法发现无用对象,并进行清除和整理。
垃圾回收相关算法
-
引用计数法
堆中的每个对象都对应一个引用计时器,当有引用指向这个对象时,引用计时器加1,当指向该对象的引用失效时(引用变为null),引用计时器减1,最后如果该对象的引用计时器的值为0,该java垃圾回收器会认为该对象是无用对象并进行回收,优点是算法简单,缺点是“循环引用的无用对象”(没有引用指向的对象互相引用)无法识别。
-
引用可达法
程序把所有的引用关系都看作一张图,从一个节点GD ROOT开始,寻找对应的引用节点,找到这个节点以后继续寻找这个节点的引用节点,当所有的引用节点寻找完毕以后,剩余的节点则被认为是没有被引用到的结点,即无用节点。
通用的分代垃圾回收机制
内存泄露
指堆内存由于某种原因程序未释放,造成内存浪费,导致运行速度减慢甚至系统崩溃等等。
this关键字
本质就是创建好的对象的地址
this的用法
普通方法中,this指调用该方法的对象
构造方法中,this指要初始化的对象
static方法中不能使用this
this()表示调用构造方法,必须要处于第一行
this是作为普通方法的隐式参数,由系统传入方法中
static关键字
静态变量/静态方法生命周期和类相同,在整个程序执行期间都有效。它有如下特点:
- 为该类的公用变量,属于类,被该类的所有实例共享,在类载入时被初始化
- static成员变量只有一份
- 一般用“类名.类变量/方法”来调用
- 在static方法中不可直接访问非static的成员
静态初始化块
构造方法用于对象的初始化,静态初始化块用于类的静态成员初始化操作,在静态初始化块中不能直接访问非static成员。
static{
#为静态成员赋值,调用静态方法
}
包机制(package、import)
包(package)相当于文件夹对文件的作用,用于管理类、用于解决类的重名问题。
JDK中的主要包
如果要使用其他包的类,需要使用import。
静态导入
用于导入指定类的静态属性和静态方法
import static java.lang.Math.*
继承
不要重新建造轮子,而是去改善它。
英文字母:extends
public class first {
public static void main(String[] args) {
Student s1 = new Student();
System.out.println(s1 instanceof Student);
}
}
class Person{
String name;
int age;
void Person(){
this.name="first";
this.age=20;
}
}
class Student extends Person{
public void output(){
System.out.println(this.age);
}
}
instanceof
用于检测该类是否继承于另一类。
要点
- 父类也称作超类、基类,子类被称为派生类
- java中只有单继承,没有像C++那样的多继承
- java中类没有多继承,但是接口有多继承
- 子类继承父类,可以得到父类的全部属性和方法(除了父类的构造方法),但不见得可以直接访问
- 如果定义一个类没有调用extends,它的父类时:java.lang.Object
方法重写override
子类的新方法把父类的方法直接覆盖掉了
第二点返回值类型小于等于父类的意思是,返回值的类型可以是父类,也可以是子类,但是父类的返回类型只能是父类及以上。
#####final关键字
- 修饰变量:该变量不能被二次赋值
- 修饰方法:只能重载,不能重写
- 修饰类:修饰的类不能被继承
#####组合
除了继承,组合也能实现代码的复用。组合的核心是“将父类对象作为子类的属性”
如果是“is -a”关系建议使用继承,“has-a”关系建议使用组合
eg:Student is a Person用继承,笔记本has a芯片用组合。
如果只考虑复用,组合更灵活一些,但是如果考虑逻辑性,用继承。
#####equals
equals()默认是比较两个对象的hashcode(地址)。但可以根据自己的要求重写equals方法。
#####toString的重写
public class first{
String name;
String pwd;
int id;
public first(String name,String pwd,int id){
this.name=name;
this.pwd=pwd;
this.id=id;
}
@Override//覆盖关键字,不用管
public String toString() {
return "first{" +
"name='" + name + '\'' +
", pwd='" + pwd + '\'' +
", id=" + id +
'}';
}
public static void main(String[] args) {
first one=new first("sunjie","123",45);
System.out.println(one.toString());
}
}
这里并没有重写,只是调用了格式,如果要重写的话就改变toString里面的内容
super关键字
- super可以看作是直接父类对象的引用,可以通过super来访问父类中被子类覆盖的方法或属性
- 使用super调用普通方法,语句没有位置限制
- 在一个类中,若是构造方法的第一行没有调用super()或this(),那么java默认都会调用super(),含义是调用父类的无参数构造方法
继承树的追溯
构造方法的调用顺序:
构造方法第一句总是:super()来调用父类对应的构造方法。所有流程是先向上追溯到Object,然后再依次向下执行类的初始化块和构造方法,直到当前的子类为止。
静态初始化块调用顺序与构造方法调用顺序一样,不再重复
子类建立之前一定会先调用父类的构造方法。
封装
理念:高内聚,低耦合(封装的越复杂,调用的时候越简单越好)
高内聚就是类的内部数据操作细节自己完成,不允许外部干涉,丢和就是仅暴露少量的方法给外部使用,尽量方便外部调用
这里的子类指不在同一个包的子类
开发封装中的简单规则
-
属性一般使用private访问权限
属性私有后,提供相应的get/set方法来访问相关属性,这些方法通常是public修饰的,以提供对属性的赋值与读取操作(boolean变量的get方法是is开头的)
-
方法:一些只用于本类的辅助性方法可以用private修饰,希望其他类调用的方法用public修饰。
多态
同一个方法调用,不同的对象行为完全不同
- 多态是方法的多态,不是属性的多态
- 多态的存在要有3个必要条件:继承,方法重写,父类引用指向子类对象
- 父类引用指向子类对象后,用该父类引用调用子类重写的方法
父类引用调用子类对象的意思是,Dog类是Animal类的子类,Animal a=new Dog(),此时a是父类的引用,它调用了子类对象。
对象的转型
- 父类引用指向子类对象,我们把这个过程称为向上转型,属于自动类型转换
- 向上转型的父类引用变量只能调用它编译类型的方法,不能调用它运行时类型的方法,这时我们需要进行强制类型的转换,称之为向下转型。
Animal animal=new Dog();//向上转型
Dog d=(Dog)animal;//向下转型
//这里的d和animal是同一个对象
抽象类和接口
抽象方法
- 使用abstract修饰的方法,没有方法体只有声明
- 定义的是一种规范,就是告诉子类必须要给抽象方法提供具体的实现
抽象类
包含抽象方法的类就是抽象类,抽象类可以包含普通属性和方法。
public abstract class Animal {
public abstract void rest();
public abstract void run();
public abstract void shout();
}
class Dog extends Animal{//子类必须实现父类的接口
@Override
public void rest() {
System.out.println("rest");
}
@Override
public void run() {
System.out.println("run");
}
@Override
public void shout() {
System.out.println("shout");
}
}
使用要点
- 有抽象方法的抽象类只能定义成抽象类
- 抽象类不能实例化,即不能用new来实例化抽象类
- 抽象类可以包含属性、方法、构造方法,但是构造方法不能用new实例,只能用来被子类调用
- 抽象类只能用来被继承
- 抽象方法必须被子类实现
接口
接口就是一组规范,所有实现类都要遵守,全部是抽象方法。
接口和实现类不是父子关系,是实现规则的关系。
声明格式
访问修饰符:是能是public或者默认
接口名:和类名采用相同命名机制
extends:接口可以多继承
常量:接口中的属性只能是常量,总是public static final修饰,不写也是
方法:接口中的方法只能是public abstract
其实和抽象类差不多,实现类调用的时候用implements,可以更好地表示现实的逻辑。
接口不能创建实例,但是可以声明类型。
Volant a2=new Angel();//Volant是接口,Angel是类
要点
- 子类通过implements来实现接口中的规范
- 接口不能创建实例,但是可用于声明引用变量类型
- 一个类实现了接口,必须要实现接口中的所有方法,并且这些方法只能是public的
- JDK1.8(不含8)之前,接口中只能包含静态常量,抽象方法,不能有普通属性、构造方法、普通方法
- JDK1.8之后,接口中包含普通的静态方法,默认方法。
接口中的默认方法
允许给接口添加一个非抽象的方法实现,只需要使用default关键字即可,这个特征又叫做默认方法(扩展方法)
默认方法和抽象方法的区别是抽象方法必须要被实现,默认方法可以重写也可以不重写。
所有子类都可以继承默认方法。
接口中的静态方法
可以在接口中直接定义静态方法的实现,这个静态方法直接属于接口(接口是特殊的类),可以通过接口名调用,如果子类中定义了相同名字的静态方法,那是完全不同的方法,不是重写,而是同名的不同的方法罢了。
子类并不继承接口中的静态方法。
接口的多继承
类只能单继承,但是接口可以多继承,子接口extends父接口,会获得父接口的一切。
字符串String类详解
String类和常量池
实际上内存分析中的”常量池“分为以下三种:全局字符串常量池、class文件常量池、运行时常量池,我们只关注运行时常量池即可。
方法 | 解释说明 |
---|---|
char charAt(int index) | 返回字符串中第index个字符 |
boolean equals(String other) | 如果字符串与other相等,返回true,否则返回false |
boolean equalslgnoreCase(String other) | 如果字符串与other(忽略大小写)相等,返回true,否则返回false |
int indexOf(String str) | 返回从头开始查找第一个子字符串str在字符串中的索引位置。如果未找到子字符串str,则返回-1 |
lastIndexOf() | 返回从末尾开始查找第一个子字符串str在字符串中的索引位置。如果未找到子字符串str,则返回-1 |
int length() | 返回字符串的长度 |
String replace(char oldChar,char newChar) | 返回一个新串,它是通过用newChar替换此字符串中出现的所有oldChar而生成的 |
boolean startsWith(String prefix) | 如果字符串以prefix开始,返回true |
boolean endsWith(String prefix) | 如果字符串以prefix结束,返回true |
String substring(int beginIndex) | 返回一个新字符串,该串包含从原始字符串beginlndex到串尾 |
String substring(int beginIndex,interesting endlndex) | 返回一个新字符串,该串包含从原始字符串beginlndex到串尾或endlndex-1的所有字符 |
String toLowerCase() | 返回一个新字符串,该串将原始字符串中的所有大写字母改成小写字母 |
String toUpperCase() | 返回一个新字符串,该串将原始字符串中的所有小写字母改成大写字母 |
String trim() | 返回一个新字符串,该串删除了原始字符串头部和尾部的空格 |
java的API文档
-
下载地址:https://www.oracle.com/java/technologies/javase-jdk8-doc-downloads.html
-
解压,docs——>api——>index.html
内部类
把一个类放在另一个类内部进行定义就称为内部类。
内部类的两个要点:
- 内部类只允许外部类直接访问,不允许同一个包中的其他类直接访问
- 内部类可以直接访问外部类的私有属性,内部类被当成其外部类的成员,但外部类不能访问内部类的内部属性
非静态内部类
非静态内部类的要点:
- 非静态内部类的对象必须寄存在一个外部类对象里。因此,如果有一个非静态内部类对象,那么一定存在对应的外部类对象。非静态内部类对象单独属于外部类的某个对象。
- 非静态内部类可以直接访问外部类的成员,但是外部类不能直接访问非静态内部类成员。
- 非静态内部类不能有静态方法、静态属性和静态初始化块
- 成员变量访问要点:
- 内部类属性:this.变量名
- 外部类属性:外部类名.this.变量名
内部类的访问:
-
外部类中定义内部类:new Inner();
-
外部类以外的地方使用非静态内部类:
Outer.Inner varname=new Outer().new Inner().
静态内部类
定义方式:
static class ClassName{
//类体
}
使用要点:
-
静态内部类可以访问外部类的静态成员,但是不能访问外部类的普通成员
-
静态内部类看作外部类的一个静态成员
-
外部类以外的地方使用非静态内部类:
Outer.Inner varname=new Outer().Inner().
匿名内部类
适合只需要使用一次的类,比如键盘监听操作等等。
语法:
new 父类构造器(实参类表)\实现接口(){
//匿名内部类类体
}
不专门创建接口的实现类,而直接在使用的时候new一个匿名的对象。
局部内部类
定义在方法内部的,作用域仅限于本方法的类称为局部内部类。
数组
数组也是对象
数组的四个特点:
- 长度是确定的。数组一旦被创建,它的大小就是不可以改变的
- 其元素的类型必须是相同类型,不允许出现混合类型
- 数组类型可以是任何数据类型,包括基本类型和引用类型
- 数组变量属于引用类型,数组也是对象,数组中的元素相当于对象的属性
声明方式
type[] arr_name;//方式一
type arr_name[];//方式二
- 在声明的时候并没有实例化任何对象,只有在实例化数组对象的时候JVM才分配空间,这时候才和长度有关。
- 声明一个数组的时候并没有数组真正被创建
- 构造一个数组必须指定长度
public class first{
public static void main(String[] args) {
int s[];//声明
s=new int[10];//定义
for (int i = 0; i < 10; i++) {
s[i]=i;
}
System.out.println(s[0]);
}
}
初始化
-
静态初始化
直接在定义数组的时候就为数组元素分配空间并赋值
int[] a={1,2,3}; Man[]mans={new Man(1,1),new Man(2,2)};
-
动态初始化
数组定义与为数组元素分配空间并赋值的操作分开进行
int[]a1=new int[2]; a1[0]=1; a1[1]=2;
-
默认初始化
数组是引用类型,它的元素相当于类的实例变量,因此数组一经分配空间,其中的每个元素也被按照实例变量同样的方式被隐式初始化。
int a2[]=new int[2];//默认值:0,0 boolean[] b=new boolean[2];//默认值:false,false
数组的遍历方式
-
for-each(专门用于读数组或容器中的所有元素)
String ss={"aa","bb"}; for(String temp:ss){ System.Out.println(temp); }
temp指正在被遍历的元素
- for-each增强for循环在遍历数组过程中不能修改数组中某元素的值
- for-each仅适用于遍历,不涉及有关索引(下标)的操作
-
普通的for循环
数组的拷贝
System.arraycopy(object src,int srcpos,object dest,int destpos,int length)
多维数组
以数组为元素的数组就是多维数组,声明方式与一维数组差不多,只不过方框数不一样。
System.out.println(Object)实际上就是调用 object的toString方法。
Comparable接口
接口中只有一个方法:
public int compareTo(Object obj),obj为要比较的对象