Java学习

JAVA笔记

JDK的安装

  1. 下载安装JDK
  2. 配置JDK环境变量

下载安装JDK

JRE 是Java的运行环境
JDK 是Java的开发环境

Java SE - 基础核心
Java ME - 移动设备/游戏/通信
Java EE - 网站开发

  1. 安装JDK ,找到安装路径 :C:\Program Files\Java\jdk-12.0.2

  2. 复制,在设置中找到高级设置,系统变量新建JAVA_HOME变量,变量值的刚刚的路径

  3. 找到Path 变量,末尾加分号(WIN10不用),添加%JAVA_HOME%\bin进去

测试

打开CMD,输入 javac,有返回值则配置完成

输出乱码

编译的时候指定编码:

javac -encoding utf-8 *.java

java格式

1
2
3
4
5
public class test1 {
public static void main(String[] args) {
System.out.println("Hello Word!");
}
}

注释

  1. 单行

//

  1. 多行

    /*
    ····
    */

  2. 文档注释

    /**

    */

Java项目导入导出

  1. 大小可变的空间在堆中开辟(String),大小固定的在栈区中开辟(int),在栈中保存内存地址
  2. 栈的存取速度比堆快

占用字节

1
2
3
4
5
6
7
8
byte :1
short :2
int:4
long:8
float:4
double:8
char:1
boolead:1

强制转换

1
2
int a = 10;
byte b = (byte)a;

++a 与 a++

1
2
3
4
5
c = ++a + b 
//先算++a ,返回结果再+b
c = a++ b
//先算a + b 给c ,然后a++

1
2
3
double c = 10.0 / 3;
System.out.print(c);
//如果10不是10.0,则输出整数

接收用户键盘输入

1
2
3
4
5
import Java.util.Scnner;
Scnneer input = Scnner(System.in); //获取Scnner对象,用来支持接受用户输入的功能
String x = input.next();//输入字符串
int x = input.nextInt();//输入数值
System.out.println(x)

判断字符相等

用== 判读的是内存地址是否相等,用str.equals(str)来判断

switch-case

1
2
3
4
5
6
7
8
9
10
switch(x){
case 1:
······
break;
case 2:
······
break;
default:
······
}

常用函数

  • Math.ceil //向上取整
  • Math.floor //向下取整
  • Math.random // 0.-0.9随机整数
  • str.split() //拆分字符串
  • str.charAt(“位置”) //获取单个字符
  • str.substring(num,num); //截取子字符串
  • str.indexOf(); //获取指定字符串的位置
  • String.valueOf(); //转换成字符串

    随机数

    Math.random();
    //或
    Random e = new Random();
    int ra2=e.nextInt(X);
    System.out.println(ra2);

修饰符

  • default (即默认,什么也不写): 在同一包内可见,不使用任何修饰符。使用对象:类、接口、变量、方法。
  • private : 在同一类内可见。使用对象:变量、方法。 注意:不能修饰类(外部类)
  • public : 对所有类可见。使用对象:类、接口、变量、方法
  • protected : 对同一包内的类和所有子类可见。使用对象:变量、方法。 注意:不能修饰类(外部类)

break 和 continue

break跳出循环
continue跳出本次循环,执行下一次循环

重载

当定义的功能相同,但参与运算的内容不同,这时就定义一个函数名称以表示其功能方便阅读。

1
2
3
4
5
6
add(int a,int b){
···
}
add(int a,int b,int c){
···
}

数组

1
2
3
int x = new int[num]; / int[] x = new int[]; / int x[] = new int[];

int x = new int[]{x1,x2,x3··}

数组有单独是数据类型,数组类型。

局部变量在栈内存中。
new 操作出来的变量都在堆内存中。

数组 x 在栈内存中存放数组地址值,在堆内存中存放数组

定义好数组后都有默认值,int 为0,等

面向对象思想

三个特征:继承,封装,多态
开发:找对象使用,没有对象就创建对象
找对象,建立对象,使用对象,维护对象的关系
具体对象就是java 在堆内存中用new 建立的实体

1
2
3
4
5
6
7
8
9
10
11
class x{
void run(){
···
}
·····
}

public static void main(){
x a = new x(); //类类型变量
}

成员变量和局部变量:
成员变量作用于整个类中,局部变量作用于函数中, 或者语句中。
成员变量在堆内存中,局部变量在栈内存中。

匿名对象使用:当对对象的方法只调用一次时,可以使用匿名对象

1
new x().run()

如果对一个对象进行多个成员的调用,必须给这个对象起个名字。
可以将匿名对象作为实际参数进行传递。

封装

是指隐藏对象的属性和实现细节,仅对外提供公共的访问方式。

好处:

  • 将变化隔离
  • 便于使用
  • 提高重用性
  • 提高安全性

封装原则

  • 将不需要对位提供的内容都隐藏起来。
  • 把属性都隐藏,提供公共方法对其访问。

this

this 代表本类对象。代表它所在函数所属对象的引用。

private

私有,权限修饰符,用于修饰类中的成员(成员变量,成员函数)私有只在本类中有效。
私有仅仅是封装的一种表现形式。

static

是一个修饰符,用于修饰成员(成员变量,成员函数)
被静态修饰的变量不在堆内存中。
当成员被静态修饰后,就多了一个调用方式,除了可以被对象调用外,还可以直接被类名调用,类名.静态成员

static的特点

  1. 随着类的加载而加载
    当类加载到内存时,static修饰的东西就在内存中开辟好了空间。
    随着类的消失而消失。
  2. 优先于对象的存在
  3. 被所有对象所共享
  4. 可以直接被类名调用

为啥不把所有都定义成static?
对内存的消耗比较大。
静态是先存在的,类是后存在的。

示例变量和类变量的区别。

主函数是静态的
主函数的定义:

  • public:代表着该函数访问权限是最大的了。
  • static:代表主函数随着类的加载就已经存在了。
  • void:主函数没有具体的返回值。
  • main:不是关键字,但是是特殊的单词,可以被JVM识别。
    函数的参数:(String[] arr):函数的参数,该数组中的元素是字符串,字符串类型的数组。
    主函数是固定格式的:JVM识别
    JVM在调用主函数时,传入的是new String[0]
    存放位置:
  • 类变量随着类的加载存在于方法区中。
  • 实例变量随着对象的建立而存在于对堆内存中。
    生命周期
  • 类变量生命周期最长,随着类的消失而消失
  • 实例变量生命周期随着对象的消失而消失
    静态使用注意事项
  • 静态方法只能访问静态成员
  • 非静态方法可以访问静态成员

什么时候定义静态变量

  • 当对象中出现共享数据时,该数据被静态所修饰、
  • 对象中的特有数据要定义成非静态存在于堆内存中。

什么时候定义静态函数

  • 当功能内部没有访问到非静态数据(对象特有数据)

当一个java文件中调用了另一个java文件,虚拟机会在当前目录或指定目录下寻找类名.java 文件,并先把他编译。
不用暴露的类方法全部私有化。

继承

提高代码复用性
让类与类之间产生关系
关键字 :extends

1
2
3
class X extends Y{
int a = 10;
}

X 是 Y 的子类,Y也叫超类
不要为了获取其他类的功能瞎鸡巴继承,必须是类与类之间有所属关系才行。

子类调用方式:
访问本类中的变量 :this.a
访问父类中的变量:super.a

子类一定要访问父类中的构造函数,因为子类要看父类是如何对数据初始化的。

final

  1. 最终,作为一个修饰符
  2. 可以修饰类,变量,函数
  3. 被final修饰的不能被继承,被覆写
  4. 被final修饰的只能赋值一次

abstract

  1. 抽象:看不懂
  2. 抽象方法一定定义在抽类中
  3. 抽象类不可以用new创建对象,因为调用抽象方法没意义

接口:interface

  1. 接口不能创建对象,子类将接口方法全部覆盖后,才可以被实例化
  2. 一个类可以同时实现多个接口
    1
    2
    3
    4
    5
    6
    7
    interface X{

    }

    interface Z extends X{

    }

    实现:implements

    1
    2
    3
    class Y implements X{

    }

内部类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class a{
class b{ //这是内部类
public void c(){

}
}
}
class a{
static class b{ //这是静态内部类
public void c(){

}
}
}
a.b obj = new a().new b(); //调用内部类
obj.c();
a.b obj = new a.b(); //调用静态内部列
obj.c();

多态

  • 事物存在的多种体现形态
  • 代码体现:父类的引用指向了自己的子类对象
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    public class Test {

    public static void main(String[] args) {
    go_eat(new dog());
    }

    public static void go_eat(Annimo a) {
    a.eat();
    }

    }

    abstract class Annimo{
    abstract void eat();
    }

    class dog extends Annimo{
    public void eat() {
    System.out.print("666");
    }

    }

1
2
Annimo c = new dog();// 向上转型
先把对象向上转形,在向下转型,不能直接向下转型

在多态中成员函数的特点:
在编译时期:参阅引用形变量所属的类中是否有调用的方法。如果有,编译通过,如没有,编译失败。
在运行时期:参阅对象所属的类中是否有调用的方法。

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
public class Test {
public static void main(String[] args) {
Fu t = new Zi();
t.m1();
t.m2();
t.m3();
}
}

class Fu{
void m1(){
System.out.println("fu 1");
}
void m2() {
System.out.println("fu 2");
}
void m3() {
System.out.println("fu 3");
}
}

class Zi extends Fu{
void m1(){
System.out.println("zi 1");
}
void m2() {
System.out.println("zi 2");
}
}

//输出结果:
zi 1
zi 2
fu 3

接口的好处

降低程序的耦合性

Object 是所有对象的直接或者间接 的父类

异常

异常是程序中出现不正常的情况。
异常的由来:问题也是现实生活中的一个具体的事物,也可以通过java类的形式进行描述,其实就是java对不正常描述后的体现

对于问题的划分,分为两种,一种是严重的问题,一种是非严重的问题,对于严重的,java通过Error类进行描述,对于非严重的,java通过Exception 类进行描述。

对于Error 一般不编写代码进行处理

异常的处理:

1
2
3
4
5
6
7
8
9
10
11
12
13
try{
需要被检测的代码
}catch(异常类,变量){
异常处理代码:(处理方式)
}finally{

}
//或者使用throws直接抛出异常
class Demo{
int div(int a,int b) throws Exception{
return a/b;
}
}

throw 和 throws的区别

throws用在函数外,thtow用在函数内

自定义错误

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//定义错误类
class Error1Exception extends Exception{
Error1Exception(String msg){
super(msg);
}
}


class T1
{
//抛出异常
static public void run(int a) throws Error1Exception{
if(a==1) {
throw new Error1Exception("错误一");
}
}

}

字符串对象String

定义任何一个字符串都是new了一个对象
以下两者相同:

1
2
String a = new String();
String a = "";
1
2
String a = "aaa"; //定义a为aaa
a = "bbb"; //aaa的值没有改变,而是a指向了bbb

equals方法用于判断两者的内存地址值是否相等,但String覆写了该方法,用于判断字符串是否相同

1
2
3
4
5
6
str.split(","); //用逗号分割字符串,返回数组
str.substring(start,stop); //截取从statr 到stop处所有字符。含头不含尾
str.toUpperCase(); //将字符串转大写
str.toLowerCase(); //将字符串转换小写
str.trim(); //去除字符串两端的多个空格
str.compareTo("String") //对两个字符串进行自然顺序的比较

instanceof

1
2
a instanceof b;
判断a类是不是b类的实例对象

问题:S1和S2有什么区别?

1
2
String s1 = "abc";
String s2 = new String("abc");

答:s1中有一个对象”abc”,s2中有两个对象new String() 和 “abc”。

package

对类文件进行分类管理
给类提供多层命名空间
写在程序文件的第一行
类名的全称是 包名.类名
包也是一种封装形式

1
package pack;

包与包之间的访问

集合

  • 为什么出现集合类?
    • 对象多了,就用集合来存,集合是存储对象的一种最常用的形式。
  • 数组和集合类都是容器,有何不同?
    • 数组虽然可以存储对象,但是长度是固定的;集合长度是可变的,数组中可以存储基本数据类型,集合只能存储对象。
  • 集合的特点
    • 集合之用于存储对象,集合长度是可变的,集合可以存储不同类型的变量。

单列集合 Collection

目录:

  • Collection

    • List
      • ArrayList
      • LinkedList
      • Vector
    • Set
      • HashSet
      • TreeSet
  • 为什么会出现这么多容易呢?

    • 因为每一个容器对数据的存储方式不同。这个存储方式称之为:数据结构。
  • List:有索引,可以存储重复元素、可以保证文件存取顺序
    • ArrayList : 底层是数组实现的,查询快,增删慢。
    • LinkedList : 底层是链表实现的,查询慢,增删快。
  • Set : 无索引,不可以存取重复元素,存取无序。
    • HashSet : 底层是哈希表 + (红黑树)实现的,无索引,不可以存储重复元素, 存取无序。
    • LinkedHashSet : 底层是哈希表 + 链表实现的,无索引,不可以存储重复元素、可以保证存取顺序。
    • TreeSet : 底层是二叉树实现,一般用于排序。
      方法:
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      创建集合:
      Collection<String> list = new ArrayList<String>();
      共性方法:
      list.add(Objeci o); //向集合中添加一个元素
      list1.addAll(list2);//把list2的所有元素添加至list1
      list2.clear();//清空集合的所有元素
      list.remove("值"); //删除list中的一个值,返回值为布尔类型,其中"值"也可以是一个集合,会删除集合中的所有元素
      list.isEmpty(); //判断集合是不是空
      lsit.contains(); //判断集合中是否包含某个元素,返回布尔类型。
      list.size(); //输出集合数量

      list集合方法:
      特点:存取有序,有索引,可存取重复元素。
      list.add(index,obj); //把obj添加至index缩影位置
      list.addAll(index,Collection); 把集合Collection所有元素添加至index的位置
      list.get(index); // 获取index索引处的内容
      list.remove(index); //返回index索引处的位置,并删除
      list.set(index,obj); //将集合index处的内容替换成obj,返回被替换的元素
      list.indexOf(obj);//查找obj在集合中出现的位置
      list.lastIndexOf(obj); //查找obj在集合中最后一次出现的位置
      list.subList(fromIndex,toIndex); // 返回集合开始(包括)到结束(不包括)的所有元素的子集合
      list.toArray(); //将集合转换为数组
      //创建list集合对象
      List<String> list = new ArrayList<String>();

      HashSet

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      //使用HashSet
      HashSet list = new HashSet();
      list.add("AAA");
      list.add("BBB");
      list.add("CCC");
      Iterator it = list.iterator();
      while (it.hasNext()) {
      System.out.println(it.next());
      }
      //输出为无序。
      HashSet是如何保证元素唯一性呢?
      是通过两个方法hashCode和equals来完成。
      如果元素的HashCode值相同,才会判断equals是否为true。
      如果元素的hashCode值不同,不会调用equals.

      TreeSet

      TreeSet:可以对Set集合中的元素进行排序。
      在使用TreeSet时,往里面存的对象必须具备比较性
      1
      2
      3
      4
      5
      6
      7
      8
      9
      //直接存元素
      TreeSet tree = new TreeSet();
      tree.add("333");
      tree.add("222");
      tree.add("111");
      Iterator it = tree.iterator();
      while(it.hasNext()) {
      System.out.println(it.next());
      }
      如果元素不可比较
      1
      2
      3
      4
      5
      6
      7
      8
      9
      		TreeSet tree = new TreeSet();
      tree.add(new Stu("张三",20));
      tree.add(new Stu("李四",31));
      //报错
      Exception in thread "main" java.lang.ClassCastException: class zhf.demo.Stu cannot be cast to class java.lang.Comparable (zhf.demo.Stu is in unnamed module of loader 'app'; java.lang.Comparable is in module java.base of loader 'bootstrap')
      at java.base/java.util.TreeMap.compare(TreeMap.java:1291)
      at java.base/java.util.TreeMap.put(TreeMap.java:536)
      at java.base/java.util.TreeSet.add(TreeSet.java:255)
      at zhf.demo.T11.main(T11.java:11)
      如果要结局,上文中Stu对象要实现Comparable接口,覆写其中的compareTo()方法,让Stu类强制具备可比较性
      compareTo方法:
  • 如果指定的数与参数相等返回0。

  • 如果指定的数小于参数返回 -1。

  • 如果指定的数大于参数返回 1。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    class Stu implements Comparable{
    String name;
    int age;
    Stu(String name,int age){
    this.name = name;
    this.age = age;
    }
    public int compareTo(Object obj){
    return 0;
    }
    }

    当主要条件相同时,一定要判断次要条件。
    当元素不具备比较性,这时需要让元素自身具备比较性 ,将比较器作为参数传递给TreeSet对象。
    当两种排序都存在时,以比较器为主

    1
    2
    TreeSet(Comparator<? super E> comparator)
    构造一个新的,空的树集,根据指定的比较器进行排序。

    自定义比较器是Comparable中的compare方法,覆写的方法是compareTo方法

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 static void main(String[] args) {
// TODO Auto-generated method stub
TreeSet tree = new TreeSet(new MyComparable()); //传入比较器
tree.add(new Stu("李四",20));
tree.add(new Stu("张三",31));
Iterator it = tree.iterator();
while(it.hasNext()) {
Stu s = (Stu)it.next();
System.out.println(s.name);
}
}

}

class Stu{
String name;
int age;
Stu(String name,int age){
this.name = name;
this.age = age;
}
}

class MyComparable implements Comparator{ //定义一个类实现Comparator接口,覆盖compar方法
public int compare(Object o1,Object o2) {
Stu s1 = (Stu)o1;
Stu s2 = (Stu)o2;
int num = s1.name.compareTo(s2.name); //比较姓名
return num;
}

自定义比较器例子:

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 void main(String[] args) {
// TODO Auto-generated method stub
TreeSet tree = new TreeSet(new Mybj());
tree.add(new Stu1("张三",20));
tree.add(new Stu1("李四",10));
Iterator it = tree.iterator();
while(it.hasNext()) {
Stu1 a = (Stu1)it.next();
System.out.println(a.age);
}
}

}
class Stu1{
int age;
String name;
Stu1(String name,int age){
this.name = name;
this.age = age;
}
}
class Mybj implements Comparator {
public int compare(Object o1,Object o2) {
Stu1 a = (Stu1)o1;
Stu1 b = (Stu1)o2;
if(a.age - b.age<0) {
return -1;
}
return 1;
}

双列集合

  • Map
    • Hashtable
      • Properties
    • HashMap
      • LinkHashMap
    • TreeMap

遍历集合 Iterator

1
2
3
hasNext(); //如果仍有元素可以迭代,则返回true
next(); //返回下一个迭代元素
remove(); //把元素从迭代器中删除

代码:

1
2
3
4
5
6
7
8
9
10
11
//迭代器遍历集合
Collection<String> a = new ArrayList<>();
a.add("aa");
a.add("bb");
Iterator<String> it = a.iterator(); // 获取迭代器对象
boolean b = it.hasNext(); //判断是否还有下一个元素
System.out.println(b);
String e = it.next(); //获取下一个元素
System.out.println(e); //aa
e = it.next(); //获取下一个元素
System.out.println(e); //bb
1
2
3
4
5
6
7
8
//迭代器删除集合
while (it.hasNext()) {
String e = it.next();
if(e.equals("bb")) {
it.remove();
}
}

反向迭代

1
2
3
4
5
ListIterator lit =  list.listIterator(list.size()); //反向迭代的迭代器
while(lit.hasPrevious()){ //判断前一个是否还有元素
Object obj = lit.previous(); //返回元素
System.out.println(obj);
}

List特有的迭代器ListIterator

List集合特有的迭代器,ListIterator 是 Iterator 的子接口。
在迭代时,不可以通过集合对象的方法操作集合中的元素。
因为会发生ConcurrentModificationException异常。

可是Iterator中的方法是有限的,如果想要添加等操作,就要用到ListIterator迭代器。

1
2
3
list.set();//修改
list.add();//添加
list.next();//返回列表中的下一个元素,并且前进光标位置。

foreach遍历集合

1
2
3
4
5
6
7
8
// 使用增强for遍历数组
String[] arr = {"aa","bb","cc","dd"};
for(String s : arr){
System.out.println(s);
}

JDK8以后:
list.forEach((String e)->P{System.out.println(e)});

Map

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
map.keySet();//返回键的集合
map.value();//返回值的集合
map.put(键,值);//添加put(键,值)
map.entrySet(); //
// 实例
Map map = new HashMap(); //创建HashMap对象
map.put("1", "Jack"); //添加put(键,值)
map.put("2", "Rose");
map.put("1", "Lucy");

//第一种方法,获取值和键的集合
Set keySets = map.keySet();
Iterator it = keySets.iterator();
while(it.hasNext()){
Object k = it.next();
Object value = map.get(k);
System.out.println(k + ":" + value);
}
//第二种方法,获取值的集合
Collection vals = map.values();
Iterator it1 = vals.iterator();
while(it1.hasNext()){
Object value = it1.next();
System.out.println(value);
}

//第三种方式
Set enSet = map.entrySet();
Iterator it2 = enSet.iterator();
while(it2.hasNext()){
Map.Entry entry = (Map.Entry)(it2.next());
Object key = entry.getKey();
Object value = entry.getValue();
System.out.println(key + ":" + value);
}

泛型

JDK1.5版本后推出的新特性,用于解决安全问题,是一个安全机制。

1
2
3
ArrayList<String> arr = new ArrayList<String>();
arr.add("5");
arr.add(5); //报错

泛型类
泛型方法
泛型静态方法
泛型接口

在不确定集合中存储元素的类型时,可以用?来代替

1
ArrayList<?> arr = new ArrayList<?>();

? : 通配符,也可以理解为占位符
?extends E : 可以接收E类型或E的子类型

基本数据类型的包装类

1
2
3
4
5
byte Byte
short short
int Integer
long Longer
boolean Boolean

JAVA IO

IO流用来处理设备之间的数据传输
Java对数据的操作是通过流的方式
Java用于操作流的对象都子IO包中
流按操作数据分为两种 - 字节流与字符流
流按流向分为 - 输入流,输出流

  • 字符流
    • Reader
    • Writer
  • 字节流
    • InputSteam
    • OutputStream
  • 找到一个专门用于操作文件的Writer子类对象 。FileWriter。后缀名是父类名,前缀名是该流对象的功能。
    由这四个类派生粗来的子类名称都是以其付类名作为子类名的后缀
    在硬盘上创建一个文件,并写入一些内容:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    //创建一个FileWriter对象,该对象一被初始化就必须要明确被操作的文件。
    FileWriter fw = new FileWriter("D:/1.txt");
    //如果该目录下有同名文件,将被覆盖。
    //该步就是在明确数据要存放的目的地。
    //第二步,使用write方法将字符串写入到流中。
    fw.write("abcde");
    fw.flush();//刷新流的缓冲
    fw.write("bcdef");
    fw.flush();
    fw.close(); //关闭流资源,但是关闭之前会刷新一次内部缓冲中的数据,flush刷新后可以继续写入,close刷新后将会流关闭。

    IO异常的处理方式
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    FileWriter fw = null; //如果在try中定义变量,那么该变量为局部变量,在finally中不能调用,所以在外部创建全局变量 
    try {
    fw = new FileWriter("D:/1.txt");
    }catch(IOException e){
    System.out.println(e.toString());
    }finally {
    try {
    if(fw!=null) {
    fw.close();
    }
    }catch(IOException e) {
    System.out.println(e.toString());
    }
    }
    文件的连续写入:
    1
    2
    3
    4
    5
    6
    FileWriter fw = new FileWriter("D:/1.txt",true);
    fw.write("aaa");
    fw.write("bbb");
    fw.write("\r\n");//换行
    fw.write("bbb");
    fw.close();
    文件的读取
    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
    	public static void main(String arg[]) throws Exception{
    FileReader reader = new FileReader("1.txt");
    FileWriter write = new FileWriter("2.txt",true);
    int a;
    while((a=reader.read())!=-1){
    write.write(a);
    }
    reader.close(); //关闭读取
    write.flush(); //刷新内存
    write.close(); //写入关闭
    }
    }

    //按行读取
    public static void main(String arg[]) throws Exception{
    FileReader reader = new FileReader("1.txt"); //读取文件流
    BufferedReader br = new BufferedReader(reader); //BufferedReader

    FileWriter write = new FileWriter("2.txt"); //写入文件流
    BufferedWriter bw = new BufferedWriter(write);//BufferedWriter

    String str;
    while((str =br.readLine())!=null){
    bw.write(str);
    bw.newLine(); //新的一行
    }
    br.close();
    bw.flush();
    bw.close();
    }
    //多个字符读取
    FileReader fr = new FileReader("D:/1.txt");
    //定义一个字符数组用于存储读到的字符。
    char[] buf = new char[20];
    int num = 0;
    //该read(char[])返回的是读到的字符个数。
    while((num=fr.read(buf))!=-1) {
    //从0号角标开始取,取字符个数个字符。
    System.out.print(new String(buf,0,num));
    }
    //文本文件拷贝

    //创建目的地。
    FileWriter fw = new FileWriter("D:/2.txt");
    //与已有文件关联
    FileReader fr = new FileReader("D:/1.txt");
    int ch = 0;
    while((ch=fr.read())!=-1) {
    fw.write(ch);
    }
    fw.close();
    fr.close();
    //文本文件拷贝方法2
    FileWriter fw = null;
    FileReader fr = null;
    try {
    fw = new FileWriter("D:/1.txt");
    fr = new FileReader("D:/2.txt");
    char[] buf = new char[1024];
    int len = 0;
    while((len=fr.read(buf))!=-1) {
    fw.write(buf,0,len);
    }
    }catch (IOException e) {
    // TODO: handle exception
    System.out.println("文件读写异常");
    }finally {
    if(fr!=null) {
    try {
    fr.close();
    } catch (Exception e2) {
    System.out.println(e2.toString());
    }
    try {
    fw.close();
    } catch (Exception e2) {
    System.out.println(e2.toString());
    }

    }
    }
    //创建文件夹
    File file = new File("FFF");
    file.mkdir();
    //创建文件
    file = new File("FFF/9.txt");
    file.createNewFile();
    知识点:
    File 类不能读写文件,只能创建文件和文件夹
    Reader是读取数据文件的抽象类
    字符输出流类都是Writer抽象类的子类
    字符流中的数据以16位字符为单位进行读写
    当输入一个字节流时,需要实现DataInput接口
    使用File类不能改变当前目录
    可以用来描述文件或者文件夹的类是File
    File类中,创建多级目录,可以通过mkdirs()方法
    InputStream等等是抽象类
    read()方法的返回值如果为-1,表示到流的末尾
    ead(char[] cbuf)方法表示将读到的多个字符存入字符数组cbuf中
    FileWriter类直接继承InputStreamReader类
    1
    Java线程
    进程:是一个正在执行中的程序
    每一个进程都有一个执行顺序,该顺序是一个执行路径,或者叫一个控制单元
    线程:就是进程中的一个独立控制单元,线程在控制着进程的执行。

JVM 启动的时候会有一个java.exe的进程
该进程中至少有一个线程负责java程序的执行。
这个线程的代码存放在main中,该线程也称为主线程
JVM启动不只一个线程,还有负责垃圾回收机制的线程

java已经提供了对线程这类事物的描述,就是Thread类。
创建线程的第一种方式:

  1. 定义继承Thread类
  2. 覆写Thread类中的run方法。
    目的:将自定义代码存放在run方法中
  3. 调用线程的start() 方法。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

public class T21 {

public static void main(String[] args) {
// TODO Auto-generated method stub
ThreadDemo01 d1 = new ThreadDemo01(); //创建线程
d1.start(); //启动线程
for(int i=0;i<=60;i++) { //主线程
System.out.println("M----" + i );
}
}

}

class ThreadDemo01 extends Thread{
public void run(){ //覆写run方法
for(int i =0;i<=60;i++) {
System.out.println("T----" + i);
}
}
}

方法二:

  1. 定义类实现Runnable接口
  2. 覆盖Runnable接口中的run方法
  3. 将Runnable接口的子对象作为实际参数传递给Thread的构造函数
  4. 调用Thread类的start方法开启线程并调用Runnable接口子类的run方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class T23 {

public static void main(String[] args) {
// TODO Auto-generated method stub
Tdemo03 a1 = new Tdemo03(); //创建对象
Thread t1 = new Thread(a1); //创建线程,传入对象
Thread t2 = new Thread(a1);
t1.start();
t2.start();
}
}

class Tdemo03 implements Runnable{
public void run() {
for(int i=0;i<=60;i++) {
System.out.println(i);
}
}

}

两个方法有什么区别,Java之支持单继承,第二种方法避免了单继承的局限性。
继承Thread:线程代码存放在Thread子类run中
实现Runnable,线程代码在接口子类的run方法中。

多个线程在抢夺CPU的执行权
多线程的一个特性:随机性

为什么要覆盖run方法呢?
Thread类用于描述线程
该类就定义了一个功能,用于存储线程要运行的代码,该存储功能就是run方法
Thread类中的run方法用于存储线程要运行的代码。

1
2
Thread t = new Thread();
t.start();

线程资源同步例子
三个老师发80本作业

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
	public static void main(String[] args) {
TeacherPackBook p = new TeacherPackBook();
new Thread(p,"老师1").start();
new Thread(p,"老师2").start();
new Thread(p,"老师3").start();

}

}

class TeacherPackBook implements Runnable{
private int book_num = 80;
@Override
public void run() {
while(true){
if(book_num>0){
Thread th = Thread.currentThread();
String th_name = th.getName();
System.out.println("正在发第" + book_num-- + "本作业");
}else {
break;
}
}
}

}

设置线程优先级:setPriority

线程的状态:

  1. 被创建 new
  2. 运行 start()
  3. 冻结 sleep(time) 进入阻塞状态
  4. 等待wait() 进入等待状态,释放同步锁
  5. 唤醒 notify()
  6. 销毁stop() 或run方法结束。
  7. 临时状态 阻塞 具备运行资格,但没有执行权
  8. 冻结 放弃了执行资格
  9. 插队 jion
  10. yield 线程进入可运行状态
    关于线程状态:
    https://www.cnblogs.com/hejing-swust/p/8038263.html
    使当前线程从执行状态(运行状态)变为可执行态(就绪状态)。cpu会从众多的可执行态里选择,也就是说,当前也就是刚刚的那个线程还是有可能会被再次执行到的,并不是说一定会执行其他线程而该线程在下一次中不会执行到了。

Java线程中有一个Thread.yield( )方法,很多人翻译成线程让步。顾名思义,就是说当一个线程使用了这个方法之后,它就会把自己CPU执行的时间让掉,让自己或者其它的线程运行。
- thread.join把指定的线程加入到当前线程,可以将两个交替执行的线程合并为顺序执行的线程。

比如在线程B中调用了线程A的Join()方法,直到线程A执行完毕后,才会继续执行线程

线程也有自己的名称:
Thread-编号
该编号从零开始。

static Thread currentThread() :获取当前线程对象
getName():获取线程名称。

打赏
  • 版权声明: 本博客所有文章除特别声明外,均采用 Apache License 2.0 许可协议。转载请注明出处!
  • © 2020-2021 ZHF
  • Powered by Hexo Theme Ayer
  • PV: UV:

请我喝杯咖啡吧~

支付宝
微信