JAVA基础
DOS命令
dir 列出当前目录下面的所有文件
cd 进入当前一级目录
cd.. 退回上一级目录
cd\ 退到根目录
md 创建文件
rd 删除文件夹
del 删除文件
del 删除文件夹下文件 选 y
del *.txt 删除固定扩展名文件
JRE JDK
JRE(JAVA Runtime Envrioment):包含JAVA类库、工具、虚拟机
JDK(JAVADevelopment Kit) JAVA开发包,包含JDK
设置临时环境变量
set classpath=c"\; 加分号表示先在环境变量里面找。找不到的话在当前目录找,
set classpath=c"\ 不加分号表示先在环境变量里面找。找不到的话不在当前目录找,
设置系统变量
classpath 如果要先要当前目录找,再到配置的目录中找的话要这样配置 .;后面再加上配置路径
注释
单行注释 //
多行注释 /* */
文档注释 /** */
JAVA中整数表现形式
二进制 由0和1组成
十进制 由0-9组成
八进制 以0开头表示
十六进制 以0x开头表示
数据类型
基本数据类型 引用数据类型
数值型 字符型 布尔型boolean 类(class) 接口(interface) 数组([])
整数类型(byte(1) short(2) int(4) long(8))-----浮点类型(float(4),double(8)) 字符型char
类型转换
在不同位的类型进行转换。会先将值类型提升为大的值类型,再进行运算
经典例题
byte b = 3;
b=b+2; 在这里运行的话 因为2默认是int类型,所以byte类型与整型运算的时候会提升为int类型进行运算 所以将运算完的返回类型再 赋值给b(小的类型)会报错。。。因此必须进行强制类型转换
在asc表中。每一个字符都有相对应的数值 'a'..97 ’A‘..64 '1' ..49
字符运算符
例子
short s = 4;
s=s+2; 编译时会报错 会执行两次运算 先+ 后=赋值
s+=2; 编译正常通过 只会执行一次运算,将左右两边的值赋值给s 左右两边值相加会执行自动类型转换
赋值运算符
int a,b,c;
a = b = c = 5 ; 同时给三个变量赋值
比较运算符
instaanceof 检查 是否是类的对象 比如"hello" instanceof String true
逻辑运算符(用于连接boolean类型的表达式)
&与
|或
!非
^异或; 两边相同,结果为假 两边不同,结果为真
&& 单&和双&&的特点 单&无论左边是真还是假,右边都会运算。而双&&左边有假。就不对右边进行运算
|| 单|两边都参与运算 双||当左边为真是,就再对右边进行运算
位运算符
左位移 << 3<<2 (3的二进制向左移2位 左移后的低位补零) 3<<2=12 6<<3=48 快速运算方法 左位移结果=位移数*2^n
右位移 >> 6>>>2 (6的二进制向左移2位 左移后的最高位补当前最高位的值,由当前最高位定 ) 3>>2=0(如果是小数,则舍弃小数位) 6>>2=1 快速运算方法 左位移结果=位移数/2^n
无符号右移 >>> 6>>>2 (6的二进制向左移2位 左移后的最高位补零)
与 & 当两个数进到与运算的时候,会先将这个数转换为二进制数 然后通进逻辑运算,比较每位的上的值,并返回
或 | 当两个数进到与运算的时候,会先将这个数转换为二进制数 然后通进逻辑运算,比较每位的上的值,并返回
异或 ^ 当两个数进到与运算的时候,会先将这个数转换为二进制数 然后通进逻辑运算,比较每位的上的值,并返回 如果一个数^另外一个数,那么得到的结果还是当前的这个数
反码 ~ (也就是!非运算) 两个数进到与运算的时候,会先将这个数转换为二进制数 然后通进逻辑运算,比较每位的上的值,并返回
两个值换位置
1.使用一个中间数,对两个数的位置进行交换
2、求出两个数的和,再减去其中一个值,就等到另外一个的值
3、使用异或的方式
int n=3,m=4;
n=n^m;
m=n^m;
n=n^m;
三元运算符(三个元素参与运算)
int x=3,y;
y=(x>3)?100:120; 在三元运算符中,结果必须是一个boolean值 如果是true返回第一个,如果是false返回第二个值
循环、条件语句
switch支持的四种类型 byte short int char
while for无限循环的几种表达形式
//其中for循环不写循环条件默认就是true
for(;;){
}
while(true){}
break;退出当前循环 continue 执行下一次循环
for循环标识一个名字 名字:for(){} 也可以指定break退出指定的循环,执行语句 break 循环的名字;
练习:等边三角形打印
JAVA存储
堆 存放的是对象
栈 存放的是基本数据 (byte short int long float double boolean char) 还有变量引其引用
常量池 代码中创建的临时常量
方法区、共享区、数据区 存放方法、静态的内容和共享数据
数组
数组的三种创建形式
int []a = new int[10];
int [] b = new int[]{1,2,3,4};
int []c ={1,2,3,4};
利用数组最得最大值,最小值
将第一个数依次和后面的数相比(不能自定义一个最大值或最小值,因为数组中的值可能会超过那个最值)
选择排序 选择排序 遵循的原则是第n个数,与他后面的所有数比较一下,最后取出一个最值,再进行第二轮比较
/**
* 选择排序 遵循的原则是第n个数,与他后面的所有数比较一下,最后取出一个最值,再进行第二轮比较
*
*/
static void method1(int[] arrays) {
for (int i = 0; i < arrays.length - 1; i++) {
for (int j = i + 1; j < arrays.length; j++) {
if (arrays[i] > arrays[j]) {
int temp = arrays[i];
arrays[i] = arrays[j];
arrays[j] = temp;
}
}
}
}
冒泡排序 遵循的原则是相邻两个数相比较,最后取出一个最值,再进行第二轮比较
/**
* 冒泡排序 遵循的原则是相邻两个数相比较,最后取出一个最值,再进行第二轮比较
*
*/
static void method2(int[] arrays) {
for (int i = 0; i < arrays.length - 1; i++) {
for (int j = 0; j < arrays.length - i - 1; j++) {
if (arrays[j] > arrays[j + 1]) {
int temp = arrays[j];
arrays[j] = arrays[j + 1];
arrays[j + 1] = temp;
}
}
}
}
数组的查找
折半查找4-7 ......
进制转换
十进制转换二进制
6转成二进制 6取余2 余0 商为3 3再取余2余1 商为1 3再取余2余0 商为1 所以值为110
十进制转换十六进制
十进制转换八进进制 ......4-8
二维数组
二维数组的几种写法
int a[][]; a为二维数组
int[][] b; b为二维 数组
int[] x, y[]; x为一维数组 y为二维数组
面向对象
变量
成员变量 存在于堆内存,作用于当前类
局部变量 存在于栈内存,作用于当前定义的成员的位置
封装
封装:隐藏事物的属性和实现细节,只提供公共的访问方式
好处:提高类重用性,方便使用,提高安全性
构造
构造代码块和构造函数的区别:
构造代码块是给所有对象进行统一初始化,
而构造函数是给对应的对象初始化,执行顺序为先构造块,后构造函数
构造代码块{} 用于共幸的方法
构造函数 类名(){}
同一个类中,调用别的构造函数
this("aaa");
static静态特点
1、随着类创建,而被创建
2、优先于对象存在
3、被所有数据共享
4、可以直接用类调用
实例化变量(对象变量)和类变量(静态变量)的区别
1、存放位置 对象变量存放于堆内存,静态变量存放于方法区
2、生命周期 对象变量随着对象消失而消失,类变量随着类消失而消失
实例化对象的步骤
Person p = new Person("wxq");
1、首先将硬盘上存在的字节码文件加载到内存当中
2、执行该类的static静态代码块(如果有的话),
3、给类person.class类进行初始化
4、在堆内在中开辟一个空间,分配内存地址
5、在堆内在中创建一个对象的特有属性,并默认初始化
6、对属性进行显示初始化(对对象的方法在方法区进行实例化)
7、对对象构造代码块初始化
8、对对应的构造函数初始化
9、将内存地址付给栈内存中的变量
帮助文档的制作
javadoc -d 目录 要显示的@内容 如@version @auther 源文件如aa.java
静态代码块 -------构造代码块--------构造方法
static {} 随着类加载而加载,且只加载一次 (编译后加载) 初始化类
代码块执行顺序 静态代码块--> 构靠代码块-->对应的构造中的代码
模板方法设计模式
在定义功能的时候,有一部分是确定的,有一部分是不确定的,需要子类去实现的,那么将这个不确定的方法暴露出去,让子类去实现。在调用的时候,子类用父类确定的方法调用子类复写过的方法。
public class Demo1 extends DongWu {
@Override
public void dongwu() {
System.out.println("猫");
}
public static void main(String[] args) {
Demo1 d = new Demo1();
d.chifan();
}
}
abstract class DongWu {
final public void chifan() {
dongwu();
System.out.println("正在吃饭");
}
public abstract void dongwu();
}
Object对象
equals与hashCode
在重写一个对象是,如果可能会对这个对象进行比较,那么建议重写equals()方法 在重写eqals()方法的时候建议也覆盖hashcode()方法
重写equals时,复写hashcode()方法的意义
先上一段equals的源代码
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String anotherString = (String)anObject;
int n = count;
if (n == anotherString.count) {
char v1[] = value;
char v2[] = anotherString.value;
int i = offset;
int j = anotherString.offset;
while (n-- != 0) {
if (v1[i++] != v2[j++])
return false;
}
return true;
}
}
return false;
}
当两个对象进行比较的时候,会先对调用hashCode方法对其hashCode码进行比较,如果hashCode码相同,就表示指针指向堆内存中的同一个地址,那么这两个对象也就相等。而如果只复写equals()方法,而不复写hachCode的时候,生成两个相同对象后,两个对象的堆内存地址不一样,会造成两个对象调用equals()方法时,返回值为false;所以必须复写hashCode()方法
自定义异常
必须是自定义类继承自Exception,或Throwable 。一般都在最下面一层处理时都要将异常抛出,交给自定义的异常处理类,在最上面一层进行自定义处理;
public class Demo4 {
public static void main(String[] args) {
try {
method(); // 异常在这里处理,使用正定异常类的方法,或者父类的方法
} catch (MyException e) {
e.printStackTrace();
}
}
static void method() throws MyException {
int a = 8, b = 0;
if (b == 0) {
throw new MyException("出现异常 信息了啊,,现在除数为零了");
}
int c = a / b;
}
}
class MyException extends Throwable {
public MyException(String eInfo) {
super(eInfo);
}
}
包Package的基本应用
编译时,指定当前包的当前类 javac -d . (也可以是别的固定路径 如:D:\\myclass)*.java 创建类中指定的包
执行的时候要加java 包名.类名
import
注意:
import只可以导入该包下面的类,不可以导入该包中的包,以及下一级包中的类
jar
cmd 使用jar查看帮助选项
将文件打成jar包 jar -cf 压缩包名(aa.jar) 包名pack1 pack2
执行jar包下面的class : 打成一个jar包,就像生成一个jar目录,将文件存到jar文件下面所以访问的时候,要加jar这层路径
多线程:
多线程创建的两种方式
extents Thread
implement Runnable
两种方法区别
在使用中建议使用第二种方法 implement Runnable 因为这种方法可以一个类中实现多个接口,避免了单继承的局限性
start() 和run()的区别与联系
run()是在jvm中创建一个方法,并不会自己调用并自己执行。
start()方法在执行的时候,首先会检查对象中有没有run方法,有的话会启动线程,调用run方法
暂停线程运行的两种方法
wait(); 使线程进行休眼状态,如果不被唤醒,则该线程一直处于休眼状态。唤醒调用的方法是Object.notify();或Object.notifyAll();唤醒此对象中已休眼的所有的线程
sleep(); 使线程进行休眼状态,休眼时间到(并获得操作权限以后)会自动执行
多线程执行流程图
使用runnable接口实现多线程的步骤
1、定义类实现runnable接口
2、覆盖run()方法
3、通过thread建议线程对象
4、将Runnable接口的子类对象作为实际参数传给thread的构靠
5、调用thread的start();开启线程并调用Runnable的run方法
使用同步块 检查多线程是否安全的步骤
1、看一下哪些是共享数据
2、看一下哪个部分是多线程运行的方法
3、明确多线程中哪些语句是操作共享数据的
多线程同步的死锁与预防死锁
1、 必须是两个以上的线程
2、要同步的线程使用同一对象
多线程睡眠与唤醒机制(睡眠与唤醒的方法必须在同步代码块或方法中执行)
睡眠方法 对象.wait(); 将本线程置与睡眠状态 除非别的线程执行notify()或notifyAll()方法,否则不能解除睡眠状态;睡眠状态的时候会放弃的执行权,将对象锁交给别人
唤醒方法
对象.notify(); 对该对象下面的单个线程唤醒(当前线程不能是睡眠状态);如果该对象下面有多个睡眠的线程,则唤醒一个线程池中睡眠的第一个线程
对象.notifyAll();对该对象下面的所有线程唤醒(当前线程不能是睡眠状态) 唤醒之后不会重头开始执行线程,只会从被唤醒的地方开始往下执行
注意:
要同时满足以下条件:
1、在run()方法中使用循环,使用每次睡眠被唤醒换重装执行循环操作
2、加判断标签,控制线程结束
程序中调用方法停止线程(生产者--消费者)
//资源类(人类),拥有数据的执行权,所以拥有对数据的处理方法
其中production()因为要被多线程调用,所以加synchronized同步方法 因为不是双线程,而是多线程,为了避免线程全部被休眠,所以使用notifyAll()方法
class Persons {
private String username;
private String password;
boolean flag = false;
public void set(String username, String password) {
this.username = username;
this.password = password;
}
int x = 0;
public synchronized void production() {
if (flag) {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
} else {
if (x == 0) {
this.username = "wxq----------------------------";
this.password = "wxq-password-------------------";
} else {
this.username = "ccc--------------";
this.password = "ccc-password-----";
}
x = (x + 1) % 2;
flag = true;
notifyAll();
}
}
public synchronized void comsumption() {
if (flag) {
System.out.println("username=" + username);
System.out.println("password=" + password);
flag = false;
notifyAll();
} else {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
多线程操作类生产者(Production) 其中changeFlag()方法用于控制线程的结束权
class Production implements Runnable {
Persons p;
Production(Persons p) {
this.p = p;
}
boolean flag = true;
public void run() {
while (flag) {
p.production();
}
}
public void changeFlag() {
this.flag = false;
}
}
多线程操作类消费者(Comsumption) 其中changeFlag()方法用于控制线程的结束权
class Comsumption implements Runnable {
Persons p;
Comsumption(Persons p) {
this.p = p;
}
boolean flag = true;
public void run() {
while (flag) {
p.comsumption();
}
}
public void changeFlag() {
this.flag = false;
}
}
调用者类
public class Demo2 {
public static void main(String[] args) {
Persons p = new Persons();
Production pro = new Production(p);
Comsumption com = new Comsumption(p);
Thread t1 = new Thread(pro);
Thread t2 = new Thread(pro);
Thread t3 = new Thread(com);
Thread t4 = new Thread(com);
t1.start();
t2.start();
t3.start();
t4.start();
try {
Thread.sleep(4000);
pro.changeFlag();
com.changeFlag();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
守护线程
setDeamon() 将一定线程定义为守护线程的方法
使用场景:
守护线程也可以称为后台线程,数据依赖于前台线程,如果前台线程结束,则守护线程自动结束(当程序中执行的所有线程都为守护线程的时候,JVM退出)
使用注意:定义守护线程必须在该线程启动前调用他
线程停止的方法
1、stop();此方法已过时
2、在线程的循环当中添加标签(判断是否继续循环,如果想停止线程,则在外部调用线程中改变标签的方法)
3、中断线程interrupt(); 当程序没有方法法回到执行状态,使用中断线程将正在休眠的线程中断休眠状态,并抛出 InterruptedException
异常供处理;
线程join()
等待该线程终止
当一个主线程中,执行了子线程的join();方法的时候,便会释放执行权(不和子线程抢资源,也就是终止自己),等子线程执行完了再执行其本身。
主要作用在于,主线 程需要子线程的数据,那么等子线程执行完,然后再执行自己线程,获取子线程的数据
线程yield()
将执行权交到别的线程(非冻结)
等别的线程释放执行权的时候自己再执行
线程优先级setPriority
可以设定的几个值有MAX_PRIORITY MIN_PRIORITY NORM_PRIORITY 初始值为5
设置优先级,可以使CPU分配执行次数多一点,并不会把所有的执行权抢过来
String
常用方法
indexOf(char c) 查找一个字符在字符串中的位置
charAt(int i) 判断一个索引处char的值
lastIndexOf(char c) 反向查找一个字符在字符串中的位置
contains(String str) 判断一个字坐串中是否包含一个字符串
isEmpty() 判断一个字符串是否为空,原理是判断字符串length
toCharArray() 将一个字符串转换为字符数组
对比最包含最多的String字符串的方法 **********************************************************
集 合
Vector
特殊方法:
Enumeration<E> | elements() 返回此向量的组件的枚举。 |
枚举就是Vector的特殊取值方式
Vector v = new Vector();
v.add("aa");
Enumeration en=v.elements();
while(en.hasMoreElements()){
System.out.println(en.nextElement());
}
Collection
特殊方法:
contains(Object elem)
如果此列表中包含指定的元素,则返回 true。
remove(index i) 在删除的时候会执行equals方法,在集合中从头开始找一遍元素,找到的话就删除,不再往下找
TreeSet
如果要对类对象进行比较,那么类必须实现Comparable接口 //该接口强制让对象具备比较性
覆盖CompareTo()方法
class Student implements Comparable {
@Override
public int compareTo(Object o) {
if (!(o instanceof Student)) {
throw new RuntimeException("不是学生对象");
}else{
//要比较的对象进行值比较。并返回值、如果要对次要的排序并且是String类型的话,那么执行CompareTo()方法即可
}
return 0;
}
}
TreeSet的比较原理
TreeSet底层使用二叉树的算法,将要存储的元素进行比较,排序后进行存储
使用二叉树进行比较的两种方式
1、使两个元素具备可比性,可以使用要比较的类实现comparable接口,并复写compareTo()方法,在方法中定义要比较的类中的元素,并返回比较结果
2、在构造TreeSet集合的时候,传进去一个自定义的比较自,自定义的比较器实现Comparator接口,并复写compara()方法,并返回比较的结果。
Comparable与Comparable的区别
Comparable通常作用于一个类中,会让一个想要比较的类对象实现Comparable接口,而让此类具备比较性
class Util implements Comparable {
@Override
public int compareTo(Object o) {
return 0;
}
}
Comparator通常用于一个自定义的比较器中,用自定义的方法来对传入的两个对象进行较
class Person implements Comparator {
@Override
public int compare(Object o1, Object o2) {
return 0;
}
}
泛型方法与泛型类
泛型类运用 当泛型类中指定了泛型的类型,那么他的带有指定泛型标签的所有的方法都将使用这个泛型类型
当类中有静态方法并使用泛型类型的参数的时候会报错,因为静态方法执行的时候,类中内容还未被加载
public class Demo3 {
public static void main(String[] args) {
Util<String> u = new Util();
u.show("aa");
u.print("ccc");
}
}
class Util<T> {
public void show(T t) {
System.out.println("show" + t);
}
public <String> void print(T t) {
System.out.println("print" + t);
}
}
泛型方法 在方法前面定义了泛型的类型的时候 那么在方法参数中带有泛型标签的类型则使用在方法前定义好的类型
class Util {
public <T> void show(T t) {
System.out.println("show" + t);
}
public <T> void print(T t) {
System.out.println("print" + t);
}
}
泛型类中 <?>与<T>的区别
<T>表示可以操作类型
<?>表示一个泛型占位符
class Util {
public <T> void show(ArrayList<T> list) {
T t = list.get(0);
System.out.println("show" + t.toString());
}
public <T> void print(ArrayList<?> t) {
t.get(0); //在这里没有接收的类型
System.out.println("print" + t.get(0));
}
}
<? extents T> 要求类型限定在T的子类
<? supter T> 要求类型限定在T的父类
Map
map.put(key,value); 返回值为替换后的值,如果当前key,value之前没有存过。则返回null
map.entrySet(); 返回此映射中包含的映射关系的 set 视图。
public static void main(String[] args) {
Map<String, String> map = new HashMap();
map.put("01", "wxq1");
map.put("02", "wxq2");
map.put("03", "wxq3");
map.put("04", "wxq4");
Set<Map.Entry<String, String>> set = map.entrySet();
Iterator<Map.Entry<String, String>> iterator = set.iterator();
while (iterator.hasNext()) {
Map.Entry<String, String> en = iterator.next();
System.out.println(en.getKey() + " " + en.getValue());
}
}
Map.Entry与Map和HashSet关系
java.util
接口 Map.Entry<K,V>
public static interface Map.Entry<K,V>
映射项(键-值对)。Map.entrySet 方法返回映射的 collection 视图,其中的元素属于此类。获得映射项引用的惟一 方法是通过此 collection 视图的迭代器来实现。这些Map.Entry 对象仅 在迭代期间有效;更正式地说,如果在迭代器返回项之后修改了底层映射,则某些映射项的行为是不明确的,除了通过setValue 在映射项上执行操作之外。
-
从以下版本开始:
- 1.2 另请参见:
-
Map.entrySet()
从上面定义的静态接口可以看出来。。Map.Entry是Map接口的一个子接口。 HashMap实现了Map接口的同时也就实现了它的子接口Entry。
所以在map中有此方法map.entrySet();
Collections
List
static
| sort(List<T> list) 根据元素的自然顺序 对指定列表按升序进行排序。 |
static
| sort(List<T> list,Comparator<? super T> c) 根据指定比较器产生的顺序对指定列表进行排序。 |
先会将无素进行排序后再进行查找,如果是对象,那么必须实现comparable接口
static
| binarySearch(List<? extendsComparable<? super T>> list, T key) 使用二进制搜索算法来搜索指定列表,以获得指定对象。 |
static
| binarySearch(List<? extends T> list, T key, Comparator<? super T> c) 使用二进制搜索算法来搜索指定列表,以获得指定对象。 |
static
| fill(List<? super T> list, T obj) 使用指定元素替换指定列表中的所有元素。 |
static
| replaceAll(List<T> list, T oldVal, T newVal) 使用另一个值替换列表中出现的所有某一指定值。 |
static void | reverse(List<?> list) 反转指定列表中元素的顺序。 |
Set Map
| reverseOrder() 返回一个比较器,它强行反转实现 Comparable 接口那些对象 collection 上的自然顺序。 |
static
| reverseOrder(Comparator<T> cmp) 返回一个比较器,它强行反转指定比较器的顺序。 |
static
| synchronizedList(List<T> list) 返回由指定列表支持的同步(线程安全的)列表。 | |
static
| synchronizedMap(Map<K,V> m) 返回由指定映射支持的同步(线程安全的)映射。 | |
static
| synchronizedSet(Set<T> s) 返回由指定 set 支持的同步(线程安全的)set。 |
static void | swap(List<?> list, int i, int j) 在指定列表的指定位置处交换元素。 |
static void | shuffle(List<?> list) 使用默认随机源随机更改指定列表的序列。 |
Arrays
static
| asList(T... a) 返回一个受指定数组支持的固定大小的列表。 |