小知识点
JDK、JRE、JVM三者关系
JDK > JRE > JVM
JDK = JRE + 开发工具集(例如Javac编译工具等)
JRE = JVM + Java SE标准类库
JVM内存的简化结构
栈:局部变量
堆:new出来的结构:对象、数组
方法区:类信息、常量池、静态域
JDK中主要的包介绍
- java.lang:包含一些Java语言的核心类,如String、Math、Integer、System、Thread,提供常用功能
- java.new:包含执行与网络相关的操作的类和接口
- java.io:包含能提供多种输入/输出功能的类
- java.util:包含一些实用工具类,如定义系统特性、接口的集合框架类、使用与日期日历相关的函数
- java.text:包含了一些Java格式化相关的类
- java.sql:包含了Java进行JDBC数据库编程的相关类/接口
- java.awt:包含了构成抽象窗口工具集(abstract window toolkits)的多个类,这些类被用来构建和管理应用程序的图形用户界面(GUI)(目前基本不用)
源文件、字节码文件
将 Java 代码编写成 .java文件(源文件)
注:一个源文件中只能有一个 java 类声明为 public,且必须是与文件同名的那个类
源文件通过 javac 命令进行编译 生成 .class文件(字节码文件)
注:.class文件可以有多个,源文件中有几个class就会生成几个.class文件
字节码文件通过 java 命令进行运行
注释
单行注释: //
多行注释: /* */
文件注释: /** */
将文件注释生成一个网页(index.html): javadoc -d 文件名 -author -version 源文件.java
命名规范
- 包名:xxxyyyzzz
- 类名、接口名: XxxYyyZzz
- 变量名、方法名: xxxYyyZzz
- 常量名: XXX_YYY_ZZZ
键盘输入(Scanner)
从键盘输入:使用 Scanner 类
例:
import java.util.Scanner; class test{ public static void main(String[] args){ Scanner scan = new Scanner(System.in); int num = scan.nextInt(); System.out.println(num); } }
switch指定类型
switch结构中的表达式,只能是 byte\short\int\char\String\枚举类型 之一
for跳出指定标识的循环
如下举例为跳出最外层循环
例:
label: for(int i=0; i<3; i++){
for(int j=0; j<10; j++){
if(j == 3) break label;
}
}
JavaBean规范
- 类是公共的 public
- 有一个无参的公共的构造类
- 有属性,且有对应的set、get方法
注:不是只能有set、get方法,还可以有其他方法
import注意的地方
- 使用java.lang包下定义的接口或类,可以省略import结构
- 使用本包下定义的接口或类,可以省略import结构
- 如果在源文件中,使用了不同包下的同名类,则必须至少有一个类需要以全类名的方式显示
- 使用"xxx.*"方式表明可以调用xxx包下的所有结构,但是如果使用的是xxx子包下的结构,则仍需要显示导入
- import static:导入指定类或接口中的静态结构 : 属性或方法
Java 中的 JUnit 单元测试(Eclipse)
步骤:
- 选中当前工程-右键选择:build path - add libraries - JUnit 4 - 下一步
- 创建 Java类,进行单元测试。(该类必须是public的,且提供公共的无参的构造器)
- 此类中声明单元测试方法。(该方法的权限是public,且没有返回值,没有形参)
- 此单元测试方法上需要声明注解: @Test,并在单元测试类中导入: import org.junit.Test
- 声明好单元测试方法以后,就可以在方法体内测试相关的代码
- 写完代码以后,左键双击单元测试方法名,右键: run as - JUnit Test
说明:执行结果无异常——绿条;执行结果出现异常——红条
interface接口
JDK7及以前
只能定义全局常量(public static final)和抽象方法(public abstract),书写时可省略
JDK8新特性
除了定义全局常量和抽象方法之外,还可以定义静态方法、默认方法(default)
- 接口中定义的静态方法只能通过接口进行调用
- 如果子类(或实现类)继承的父类和实现的接口中声明了同名同参的方法,且子类没有重写此方法,默认调用父类中同名同参的方法
- 在实现类的方法中调用接口中被重写的默认方法(Xxx.super.xxx();)
接口与接口之间可以继承,且可以多继承
异常处理
常用的异常对象处理方式:String getMessage()、printStackTrace()
finally:处理像数据库连接、输入输出流、网络编程Socket等资源,JVM不能自动回收,我们需要自己手动的进行资源的释放
机制
- try-catch-finally
- throws
- 手动抛出异常:throw
- 自定义异常类(继承现有异常类、有序列号、空参构造器、一个形参构造器)
并行和并发区别
并行:多个CPU同时执行多个任务(多个人同时做不同的事)。
并发:一个CPU(采用时间片)同时执行多个任务(秒杀、多个人做同一件事)。
java.util.Arrays常用方法
- boolean equals(int[] a, int[] b):判断两个数组是否相等
- String toString(int[] a):输出数组信息
- void fill(int[] a, int val):将指定的值填充到数组之中
- void sort(int[] a):对数组进行排序
- int binary Search(int[] a, int key):对排序后的数组进行二分法检索指定的值
java.util.Date
常用构造器
- Date(): 创建一个对应当前时间的Date对象
- Date(xxxxxxxxL): 创建一个指定毫秒数的Date对象
常用方法
- toString(): 显示当前的年、月、日、时、分、秒
- getTime(): 获取当前Date对象对应的毫秒数(时间戳)
util.Date-->sql.Date
Date date = new Date();
java.sql.Date date1 = new java.sql.Date(date.getTime());
格式化
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
数据类型、数组(注意点)
基本数据类型
整型默认为Int,浮点型默认为Double
long类型变量声明时必须以"l"或"L"结尾
float类型变量声明时必须以"f"或"F"结尾
char类型只能表示一个字符,注:char c = '' //编译不通过
char类型可以用 Unicode 值来表示字符型常量(例:char c = '\u0043' 表示 'C')
自动类型提升
自动类型提升:byte、short、char-->int-->long-->float-->double
数组默认初始化值
- 整型:0
- 浮点型:0.0
- char 型:0或'\u0000',而非'0'
- boolean 型:false
- String 型(引用型):null
包装类
针对八种基本数据类型定义相应的引用数据类型
基本数据类型-->包装类: 调用包装类的构造器(自动装箱)
包装类-->基本数据类型: 调用包装类的xxxValue()(自动拆箱)
基本数据类型、包装类-->String类型: 调用String重载的valueOf(Xxx xxx)
String类型-->基本数据类型、包装类: 调用包装类的parseXxx(String s)
Integer
内部定义了IntegerCache结构,IntegerCache中定义了Integer[],保存了从-128~127范围的整数。如果我们使用自动装箱的方式,给Integer赋值的范围在-128~127范围内,可以直接使用数组中的元素,不用再去new了。
运算(注意点)
取余
%取余运算:结果的符号与被模数的符号相同
加法
变量+1,一般用 变量++;
变量+2,一般用 变量 += 2;(不会改变变量本身的数据类型)
例:
int i=1;
i *= 0.1;
System.out.rintln(i); //0 因为 *= 不改变变量本身数据类型,因此运算之后为0.1,截取整数部分为0
i++;
System.out.rintln(i); //1
与
&:逻辑与 &&:短路与
相同点:运算结果相同,当符号左边是 true 时,二者都会执行符号右边的运算
不同点:当符号左边是 false 时,&继续执行符号右边的运算;&&不再执行符号右边的运算
随机数
随机数的获取:[a,b]
(int)Math.random() * (b - a + 1) + a
例:
[10,99]
int value = (int)(Math.random() * 90 + 10);运算过程:[0.0,1.0) --> [0.0,90.0) --> [10.0,100.0) --> [10,99]
== 和 equals() 的区别
==: 运算符
- 可以使用在基本数据类型变量和引用数据类型变量中
- 如果比较的是基本数据类型变量,比较两个变量保存的数据是否相等(不一定类型要相同);如果比较的是引用数据类型变量,比较两个对象的地址值是否相同,即两个引用是否指向同一个对象实体
equals() : 方法
- 只能适用于引用数据类型
- Object类中 equals() 方法和==的作用是相同的:比较两个对象的地址值是否相同,即两个引用是否指向同一个对象实体
- String\Date\File\包装类等都重写了 Object 类中的 equals() 方法。重写以后,比较的不是两个引用的地址是否相同,而是比较两个对象的“实体内容”是否相同
- 通常情况下,比较两个对象的“实体内容”是否相同,就需要对 Object 类中的 equals() 方法进行重写
String
类型转换
String-->char[]: 调用String的toCharArray()
char[]-->String: 调用String的构造器
String-->byte[]: 调用String的getBytes()
byte[]-->String: 调用String的构造器
String/StringBuffer/StringBuilder三者的异同
String: 不可变的字符序列;底层使用char[]存储
StringBuffer: 可变的字符序列;线程安全的,效率低;底层使用char[]存储
StringBuilder: 可变的字符序列;jdk5.0新增的,线程不安全的,效率高;底层使用char[]存储
效率:StringBuilder>StringBuffer>String
类和对象
创建类的对象
new + 构造器
例:
Person p = new Person()(其中,Person()就是构造器)
匿名对象
没有显示的名字,只能调用一次
访问权限
范围从小到大:private、缺省(default)、protected、public
private:类内部
缺省:类内部、同一个包
protected:类内部、同一个包、不同包的子类
public:类内部、同一个包、不同包的子类、同一个工程
注:只能用缺省、public修饰类
属性赋值的先后顺序
默认初始化->显示初始化/在代码块中赋值->构造器中赋值->通过"对象.属性"的方式赋值
调用构造器
可以显式地使用"this(形参列表)"方式,调用本类中指定的其他构造器,且必须声明在当前构造器的首行,最多只能调用一个其他构造器
方法重写
子类对父类方法的重写,方法名、形参列表都相同
- 子类中重写的方法权限修饰符不小于父类中被重写的方法的权限修饰符(特殊情况:子类不能重写父类中声明为private权限的方法)
- 父类被重写方法的返回值是void或基本数据类型时,子类必须与父类一致;父类被重写的方法的返回值是A类型时,子类重写的方法的返回值可以是A类或A类的子类
- 子类重新的方法抛出的异常类型不大于父类被重写方法抛出的异常类型
重载与重写的区别
重载:编译期绑定(早绑定/静态绑定)
重写:运行期绑定(晚绑定/动态绑定)
对象的多态性
父类的引用指向子类的对象
虚拟方法
子类中定义了与父类同名同参的方法,在多态情况下,将此时父类的方法称为虚拟方法
instanceof关键字
使用情境:为了避免父类在向下转型时出现ClassCastException的异常,我们在向下转型之前,先进行instanceof的判断,若为true,则进行向下转型,若为false,则不进行向下转型。
使用说明:a instanceof A:判断对象a是否是类A的实例,若是,则返回true,若不是,则返回false
static
静态方法中只能调用静态属性,静态方法中不能使用this、super关键字
静态代码块( 格式:static {} )
- 内部可以有输出语句
- 随着类的加载而执行,且只执行一次
- 作用:初始化类的信息
- 如果一个类里面定义了多个静态代码块,则按照声明的先后顺序执行
- 静态代码块的执行要优先于非静态代码块的执行
- 静态代码块中只能调用静态的属性、方法,不能调用非静态的结构
非静态代码块( 格式:{} )
- 内部可以有输出语句
- 随着对象的创建而执行
- 没创建一个对象,就执行一次非静态代码块
- 作用:可以在创建对象时,初始化对象的属性
- 如果一个类里面定义了多个非静态代码块,则按照声明的先后顺序执行
- 非静态代码块中可以调用静态的属性、方法,或非静态的属性、方法
final关键字:
- 修饰类:此类不能被其他类所继承
- 修饰方法:此方法不能被重写
- 修饰属性:可以赋值的位置有——显式初始化、代码块中初始化、构造器中初始化
-
修饰形参:表明此形参是一个常量,当我们调用此方法时,给常量形参赋一个实参,一旦调用以后,就只能在方法体内使用此形参,但不能进行重新赋值
成员内部类
例:
class Person{
static class Body{
}
class Feet{
}
}创建实例格式:
1. Person.Body body = new Person.Body();
2. Person p = new Person();
Person.Feet feet = p.new Feet();
局部内部类 (方法内、代码块内、构造器内)
注意点:在局部内部类的方法中如果调用局部内部类所声明的方法中的局部变量,要求此局部变量声明为final的
函数(注意点)
可变个数形参
- 格式:数据类型 ... 变量名 (可识别0到多个相同数据类型的参数)
- 可变个数形参与本类中方法名相同,形参类型也相同的数组之间不构成重载,即两者不能共存
- 可变个数形参在方法的形参中,只能声明在末尾且只能有一个
值传递机制
如果参数是基本数据类型,此时实参赋值给形参的是实参真实存储的数据值
如果参数是引用数据类型,此时实参赋值给形参的是实参存储数据的地址值
设计模式
MVC
模型层 model(主要处理数据)
- 数据对象封装 model.bean/domain
- 数据库操作类 model.dao
- 数据库 model.db
视图层 view(显示数据)
- 相关工具类 view.utils
- 自定义view view.ui
控制层 controller (处理业务逻辑)
- 应用界面相关 controller.activity
- 存放fragment controller.fragment
- 显示列表的适配器 controller.adapter
- 服务相关的 controller.service
- 抽取的基类 controller.base
单例
采取一定的方法保证在整个软件系统中,对某个类只能存在一个对象实例。
饿汉式
- 私有化类的构造器
- 内部创建静态的类的对象 ( private static Xxx xxx = new Xxx() )
- 提供公共的静态的方法,返回类的对象
懒汉式
- 私有化类的构造器
- 声明静态的类的对象,没有初始化 ( private static Xxx xxx = null )
- 提供公共的静态的方法,返回类的对象(有的话直接返回对象,没有的话 new一个)
线程
多线程的创建
方法一
class MyThread extends Thread{
@Override
public void run(){
}
}
在main方法中:
MyThread m = new MyThread();
m.start();
方法二(优先选择)
class MyThread implements Runnable{
@Override
public void run(){
}
}
在main方法中:
MyThread m = new MyThread();
new Thread(m).start();
方法三
class MyThread implements Callable{//可以有返回值
@Override
public Object call() throws Exception{
int sum=0;
return sum;
}
}
在main方法中:
MyThread m = new MyThread();
FutureTask futureTask = new FutureTask(m);
new Thread(futureTask).start;
方法四:(使用线程池)
class MyThread implements Runnable{
@Override
public void run(){
}
}
在main方法中:
ExecutorService service = Executors.newFixedThreadPool(10);//提供指定线程数量的线程池 service.execute(new MyThread());//适合用于Runnable
service.submit();//适合用于Callable
service.shutdown();//关闭连接池
线程的常用方法
- start(): 启动当前线程;调用当前线程的run()
- run(): 通常需要重写Thread类中的此方法,将创建的线程要执行的操作声明在此方法中
- currentThread(): 静态方法,返回执行当前代码的线程
- getName(): 获取当前线程的名字
- setName(): 设置当前线程的名字
- yield(): 释放当前CPU的执行权
- join(): 在线程a中调用线程b的join(),此时线程a就进入阻塞状态,直到线程b完全执行完之后,线程a才结束阻塞状态
- sleep(long millitime): 让当前线程“睡眠”指定的millitime毫秒,在指定的millitime毫秒时间内,当前线程是阻塞状态
- isAlive(): 判断当前线程是否存活
线程的优先级
MAX_PRIORITY: 10
MIN_PRIORITY: 1
NORM_PRIORITY: 5
getPriority(): 获取当前线程的优先级
setPriority(): 设置当前线程的优先级
解决线程安全问题
方法一
同步代码块——多个线程共用的任何一个类的对象
synchronized(同步监视器){
//需要被同步的代码(操作共享数据的代码)
}
方法二
同步方法:如果操作共享数据的代码完整的声明在一个方法中,我们不妨将此方法声明同步的。(非静态的同步方法,同步监视器是this;静态的同步方法,同步监视器是类本身)
方法三
Lock锁:实例化ReentrantLock-->调用锁定方法lock()-->调用解锁方法unlock()
优先使用顺序:Lock-->同步代码块-->同步方法
线程通信的方法
- wait(): 一旦执行此方法,当前线程就进入阻塞状态,并释放同步监视器
- notify(): 一旦执行此方法,就会唤醒被wait的一个线程,如果有多个线程被wait,就会唤醒优先级较高的线程
- notifyAll(): 一旦执行此方法,就会唤醒所有被wait的线程
sleep()与wait()的异同
同:一旦执行方法,都可以使当前线程进入阻塞状态
异:Thread类中声明sleep(),Object类中声明wait();sleep()可以在任何需要的场景下调用,wait()必须使用在同步代码块或同步方法中;如果两个方法都使用在同步代码块或同步方法中,sleep()不会释放同步监视器,wait()会释放同步监视器。
参考:尚硅谷Java入门视频教程(在线答疑+Java面试真题)_哔哩哔哩_bilibili
(该视频讲的非常详细了,有兴趣的小伙伴可以关注一下!本片文章也是在学习该套视频的基础上记录的~)