不废话,直接进入正题。
目录
day1-java基础语法
public类要求文件名类名一致。
注释
//单行注释 /* 多行注释 多行注释 */ /** *文档注释 */
数据类型
多变量定义与赋值
int a,b; a=10; b=20; int c=30,d=40;
键盘录入
import java.util.Scanner; public class ScannerDemo { public static void main(String[] args) { //创建对象 Scanner sc = new Scanner(System.in); //接收数据 int a = sc.nextInt(); //输出数据 System.out.println(a); } }
关于String[] args:其实很简单,main()方法中的字符串数组类型的参数就是java命令的参数,使用java命令的方式运行main()方法,会将java命令的参数入参到Java main()方法的字符串数组参数中。
day2-java基础语法
类型转换
自动类型转换:小类型自动转大类型。
强制类型转换:大类型转小类型。
强制类型转换格式:目标数据类型 变量名 = (目标数据类型)值或者变量;
double num1 = 5.5; int num2 = (int) num1; // 将double类型的num1强制转换为int类型 System.out.println(num2);//输出5
三个重要的ascii码
a--97
A--65
0--48
字符的➕操作和字符串的➕操作
// 可以通过使用字符与整数做算术运算,得出字符对应的数值是多少 char ch1 = 'a'; System.out.println(ch1 + 1); // 输出98,97 + 1 = 98 char ch2 = 'A'; System.out.println(ch2 + 1); // 输出66,65 + 1 = 66 char ch3 = '0'; System.out.println(ch3 + 1); // 输出49,48 + 1 = 49
System.out.println(1 + 99 + "年黑马"); // 输出:100年黑马 System.out.println(1 + 2 + "itheima" + 3 + 4); // 输出:3itheima34 // 可以使用小括号改变运算的优先级 System.out.println(1 + 2 + "itheima" + (3 + 4)); // 输出:3itheima7
短路逻辑运算符
- 逻辑与&,无论左边真假,右边都要执行。
- 短路与&&,如果左边为真,右边执行;如果左边为假,右边不执行。
- 逻辑或|,无论左边真假,右边都要执行。
- 短路或||,如果左边为假,右边执行;如果左边为真,右边不执行。
流程控制语句
- 分支结构if,switch
- 循环结构while,do while
switch (表达式) { case 1: 语句体1; break; case 2: 语句体2; break; ... default: 语句体n+1; break; }
- 跳转控制语句
-
- 跳转控制语句(break)
跳出循环,结束循环
-
- 跳转控制语句(continue) ( 跳过某次循环体内容的执行 )
跳过本次循环,继续下次循环
- 标识循环体,退出特定循环
Random随机数
用法类似scanner
使用步骤: 1. 导入包 import java.util.Random; 2. 创建对象 Random r = new Random(); 3. 产生随机数 int num1 = r.nextInt(10);//产生0-9随机数 int num2 = r.nextInt(10) + 1;//产生1-10随机数
day3--和方法数组
数组
- 数组的动态初始化
格式:数据类型[] 数组名 = new 数据类型[数组长度];
- 静态初始化
格式1:数据类型[] 数组名 = new 数据类型[]{元素1,元素2,...};
格式2: 数据类型[] 数组名 = {元素1,元素2,...};
获取数组长度:arr.length
方法
- 格式:
修饰符 返回值类型 方法名(参数){ 方法体; return 数据; } //举例------ public static void method(){ int a = 10; int sum = a+1; return ; }
方法重载
方法重载指同一个类中定义的多个方法之间的关系,满足下列条件的多个方法相互构成重载
- 多个方法在同一个类中
- 多个方法具有相同的方法名
- 多个方法的参数不相同,类型不同或者数量不同
参数传递
number输出100
- 基本数据类型的参数,形式参数的改变,不影响实际参数
arr[1]输出200
- 对于引用类型的参数,形式参数的改变,影响实际参数的值
day4--面向对象
类的定义
public class Student { // 属性 : 姓名, 年龄 // 成员变量: 跟之前定义变量的格式一样, 只不过位置发生了改变, 类中方法外 String name; int age; // 行为 : 学习 // 成员方法: 跟之前定义方法的格式一样, 只不过去掉了static关键字. public void study(){ System.out.println("学习"); } }
对象的创建
格式:类名 对象名 =new 类名();
调用格式:对象名.成员变量
对象名.成员方法();
对象内存图
成员变量和局部变量
成员变量---堆区
局部变量---栈区
previate封装
public class student { String name; private int age; public int getAge() { return age; } public void setAge(int age) { if(age<0||age>120){ System.out.println("你的年龄有误"); }else{ this.age = age; } } public void show(){ System.out.println(name+","+age); } }
public class StudentDemo { @Test public void test(){ student s = new student(); s.name = "林清霞"; s.setAge(30); s.show(); } }
this关键字
this修饰的变量用于指代成员变量,其主要作用是(区分局部变量和成员变量的重名问题)
- 方法的形参如果与成员变量同名,不带this修饰的变量指的是形参,而不是成员变量
- 方法的形参没有与成员变量同名,不带this修饰的变量指的是成员变量
构造方法
格式注意 :
- 方法名与类名相同,大小写也要一致
- 没有返回值类型,连void都没有
- 没有具体的返回值(不能由retrun带回结果数据)
执行时机 :
- 创建对象的时候调用,每创建一次对象,就会执行一次构造方法
- 不能手动调用构造方法
class Student{ public Student() { System.out.println("无参构造方法"); } }
注: 1. 如果一个类中没有编写任何构造方法, 系统将会提供一个默认的无参数构造方法
2. 如果手动编写了构造方法, 系统就不会再提供默认的无参数构造方法了
day5--Scanner和String
Scanner类
-
- next():遇到空格和tab键将不再录入数据
- nextLine():可以将完整数据接收过来,结束标记:回车换行符
- nextInt():接收整数
String类
- java中所有双引号字符串,都是String类的对象
- 通过构造方法创建 :通过 new 创建的字符串对象,每一次 new 都会申请一个内存空间,虽然内容相同,但是地址值不同
- 直接赋值方式创建 :以“”方式给出的字符串,只要字符序列相同(顺序和大小写),无论在程序中出现几次,JVM都只会建立一个String对象,并在字符串池中维护。
- == 比较基本数据类型:比较的是具体的值
- == 比较引用数据类型:比较的是对象地址值
s1.equals(s2) //比较字符串的内容,区分大小写。 public char charAt(int index)//获取字符串的每个字符 String start = telString.substring(0,3); //字符串截取 String end = telString.substring(7);//表示从第七位开始截取 String result = s.replace("TMD","***"); //字符串替换 String[] sArr = stuInfo.split(","); //字符串切割,按逗号切割
Stringbuilder类
- 当对字符串进行修改的时候,需要使用 StringBuffer 和 StringBuilder 类。
- 和 String 类不同的是,StringBuffer 和 StringBuilder 类的对象能够被多次的修改,并且不产生新的未使用对象。
- 在使用 StringBuffer 类时,每次都会对 StringBuffer 对象本身进行操作,而不是生成新的对象,所以如果需要对字符串进行修改推荐使用 StringBuffer。
- StringBuilder 类在 Java 5 中被提出,它和 StringBuffer 之间的最大不同在于 StringBuilder 的方法不是线程安全的(不能同步访问)。
- 由于 StringBuilder 相较于 StringBuffer 有速度优势,所以多数情况下建议使用 StringBuilder 类。
- append()/insert()/delete()类似一个c++的vector
- toString() 把stringbuilder转成string
day6--继承
继承和super
一旦子类A继承父类B以后,子类A中就获取了父类B中声明的所有属性和方法。
特别的,父类中声明为private的属性或方法,子类继承父类以后,仍然认为获取了父类中私有的结构。只有因为封装性的影响,使得子类不能直接调用父类的结构而已。
java只支持单继承和多层继承,不允许多重继承。
- 语法:
class 子类名 extend 父类名{;}
使用一个变量会先从方法内部找,再到本类,再到父类。
子类中所有的构造方法默认都会访问父类中无参的构造方法
- super和this
super:父类的
this:成员变量
this(…) - 访问本类构造方法
super(…) - 访问父类构造方法
注意: this(…)super(…) 必须放在构造方法的第一行有效语句,并且二者不能共存
前者用来访问父类成员,后者访问本类成员
方法重写
子类出现了和父类相同的方法声明。(方法名一样,参数列表也必须一样)
Override注解:用来检测当前的方法是否是重写的方法。
重写注意事项:
- 私有方法不能被重写(父类私有成员子类是不能继承的)
- 子类方法访问权限不能更低(public > 默认 > 私有)
- 静态方法不能被重写,如果子类也有相同的方法,并不是重写的父类的方法
权限修饰符
抽象类
在Java中,一个没有方法体的方法应该定义为抽象方法,而类中如果有抽象方法,该类必须定义为抽象类!
抽象方法:方法没有方法体。
抽象类:有抽象方法的类。
抽象类和抽象方法必须用abstract修饰。
//抽象类的定义 public abstract class 类名 {} //抽象方法的定义 public abstract void eat();
- 抽象类中不一定有抽象方法,有抽象方法的类一定是抽象类
- 抽象类不能实例化
- 抽象类可以有构造方法
- 抽象类的子类,要么重写抽象类中的所有抽象方法,要么是抽象类
final
static关键字
day7--接口和多态
接口
Java中接口存在的两个意义
1. 用来定义规范
2. 用来做功能的拓展
接口的成员特点:
接口举例:
定义语法:public interface 接口名{ ... }
public interface Inter { public static final int NUM = 10; public abstract void show(); }
实现类:public class 类名 implements 接口名{ ... }
class InterImpl implements Inter{ public void method(){ // NUM = 20; System.out.println(NUM); } public void show(){ } }
接口中的静态方法只能通过接口名调用,不能通过实现类调用。
接口中的默认方法:
- 默认方法不是抽象方法,所以不强制被重写。但是可以被重写,重写的时候去掉default关键字
- public可以省略,default不能省略
- 如果实现了多个接口,多个接口中存在相同的方法声明,子类就必须对该方法进行重写
接口中私有方法
Java 9中新增了带方法体的私有方法,这其实在Java 8中就埋下了伏笔:
Java 8允许在接口中定义带方法体的 默认方法和静态方法。这样可能就会引发一个问题:当两个默认方法或者静态方法中包含一段相同的代码实 现时,程序必然考虑将这段实现代码抽取成一个共性方法,而这个共性方法是不需要让别人使用的,因此用私有给隐藏起来,这就是Java 9增加私有方法的必然性
默认方法可以调用私有的静态方法和非静态方法
静态方法只能调用私有的静态方法
多态
多态前提:
-
- 有继承或实现关系
- 有方法重写
- 有父类引用指向子类对象
class Animal { public void eat(){ System.out.println("动物吃饭"); } }
class Cat extends Animal { @Override public void eat() { System.out.println("猫吃鱼"); } }
public class Test1Polymorphic { /* 多态的前提: 1. 要有(继承 \ 实现)关系 2. 要有方法重写 3. 要有父类引用, 指向子类对象 */ public static void main(String[] args) { // 当前事物, 是一只猫 Cat c = new Cat(); // 当前事物, 是一只动物 Animal a = new Cat(); a.eat(); } }
成员访问特点:
多态中的转型:
- 向上转型
父类引用指向子类对象就是向上转型(多态)
- 向下转型
格式:子类型 对象名 = (子类型)父类引用;
转型风险及解决:
如果被转的引用类型变量,对应的实际类型和目标类型不是同一种类型,那么在转换的时候就会出现
ClassCastException
解决方案
- 关键字
instanceof
- 使用格式
变量名 instanceof 类型
通俗的理解:判断关键字左边的变量,是否是右边的类型,返回boolean类型结果
abstract class Animal {
public abstract void eat();
}
class Dog extends Animal {
public void eat() {
System.out.println("狗吃肉");
}
public void watchHome(){
System.out.println("看家");
}
}
class Cat extends Animal {
public void eat() {
System.out.println("猫吃鱼");
}
}
public class Test4Polymorpic {
public static void main(String[] args) {
useAnimal(new Dog());
useAnimal(new Cat());
}
public static void useAnimal(Animal a){
// Animal a = new Dog();
// Animal a = new Cat();
a.eat();
//a.watchHome();
// Dog dog = (Dog) a;
// dog.watchHome(); // ClassCastException 类型转换异常
// 判断a变量记录的类型, 是否是Dog
if(a instanceof Dog){
Dog dog = (Dog) a;
dog.watchHome();
}
}
}
内部类
内部类
局部内部类
匿名内部类
Lambda表达式
所需类型只能是接口
(可以放参数)->{ //...代码块 }
具体看文档
day8--异常
概述异常
什么是异常
在程序运行过程中出现的错误,称为异常。异常就是程序运行过程中出现了不正常现象导致程序的中断。
在Java中,把各种异常现象进行了抽象形成了异常类。
异常的分类
异常主要分为:错误、一般性异常(受控异常)、运行时异常(非受控异常)
- 错误
如果应用程序出现了Error,那么将无法恢复,只能重新启动应用程序,最典型的Error的异常是:OutOfMemoryError
- 受控异常
这种异常属于一般性异常,出现了这种异常必须显示的处理,不显示处理java程序将无法编译通过。编译器强制普通异常必须try…catch处理,或用throws声明继续抛给上层调用方法处理,所以普通异常也称为checked异常。
- 非受控异常
非受控异常也即是运行时异常(RuntimeException),这种系统异常可以处理也可以不处理,所以编译器不强制用try…catch处理或用throws声明,所以系统异常也称为unchecked异常。
此种异常可以不用显示的处理,例如被0除异常,java没有要求我们一定要处理, 当出现这种异常时,肯定是程序员的问题,也就是说,健壮的程序一般不会出现这种系统异常。
异常的处理
非受控异常(运行时异常)不需要预处理,通过规范的代码可以避免产生这种异常
受控异常(编译时异常)必须预处理,否则编译报错,有两种预处理方式 :
- 捕获处理
- 抛出处理
try、catch和finally
异常的捕获和处理需要采用try和catch来处理,具体格式如下:
try { //try中包含了可能产生异常的代码 } catch (OneException e) { //catch可以有一个或多个,catch中是需要捕获的异常 } catch (TwoException e) { } finally { }
- 当try中的代码出现异常时,出现异常下面的代码不会执行,马上会跳转到相应的catch语句块中,如果没有异常不会跳转到catch中。
- finally表示,不管是否出现异常,finally里的代码都执行,finally和catch可以分开使用,但finally必须和try一块使用,如下格式使用finally也是正确的
详细说明:
private static void testException2() { try { //1、对可能产生异常的代码进行检视 //2、如果try代码块的某条语句产生了异常, 就立即跳转到catch子句执行, try代码块后面的代码不再执行 //3、try代码块可能会有多个受检异常需要预处理, 可以通过多个catch子句分别捕获 } catch (异常类型1 e1) { //捕获异常类型1的异常, 进行处理 //在开发阶段, 一般的处理方式要么获得异常信息, 要么打印异常栈跟踪信息(e1.printStackTrace()) //在部署后, 如果有异常, 一般把异常信息打印到日志文件中, 如:logger.error(e1.getMessage()); } catch (异常类型2 e1) { //捕获异常类型2的异常, 进行处理 //如果捕获的异常类型有继承关系, 应该先捕获子异常再捕获父异常 //如果没有继承关系, catch子句没有先后顺序 } finally { //不管是否产生了异常, finally子句总是会执行 //一般情况下, 会在finally子句中释放系统资源 } }
异常捕获顺序
一般按照由小到大的顺序,也就是先截获子异常,再截获父异常
将IOException放到前面,会出现编译问题,因为IOException是FileNotFoundException的父类,所以截获了IOException异常后,IOException的子异常都不会执行到,所以再次截获FileNotFoundException没有任何意义
异常的截获一般按照由小到大的顺序,也就是先截获子异常,再截获父异常。
另外,关闭流资源fis.close()是在finally语句块中处理的。
throws抛出异常
格式:throws 异常类名;
该格式写在方法定义处,表示声明一个异常。
在定义方法时,如果方法体中有受检(编译时)异常需要预处理,可以捕获处理,也可以抛出处理。
处理异常时,使用throws抛出处理:
- 谁调用这个方法,谁负责处理该异常
- 在定义方法时,把异常抛出就是为了提醒方法的使用者,有异常需要预处理
在处理异常时,是选择捕获处理还是抛出处理
- 一般情况下,在调用其他方法时,如果被调用的方法有受检(编译时)异常需要预处理,选择捕获处理,因为你调用了方法, 你负责处理该异常。
- 在定义方法时,如果方法体中有受检异常需要预处理,可以选择捕获 ,也可以选择抛出处理。如果方法体中通过throw语句抛出了一个异常对象,所在的方法应该使用throws声明该异常。
throw抛出异常对象
格式:throw new 异常();
该格式写在方法内,表示当前代码手动抛出一个异常,下面的代码就不用执行了。
Throwable成员方法
自定义异常
自定义异常通常继承于Exception或RuntimeException,到底继承那个应该看具体情况来定。
自定义异常类可以有自己的变量和方法来传递错误代码或传递其它异常相关信息。实际工作中,都会自定义异常类来处理异常。
步骤:
- 定义异常类
- 写继承关系
- 空参构造
- 带参构造
/** * 自定义受控异常(编译时、检查时异常(checkedException)),继承Exception */ class MyCheckedException extends Exception { public MyCheckedException() { //调用父类的默认构造函数 super(); } public MyCheckedException(String message) { //手动调用父类的构造方法 super(message); } }
/** * 自定义非受控异常(运行时异常-unCheckedException) */ class MyRuntimeException extends RuntimeException { public MyRuntimeException() { //调用父类的默认构造函数 super(); } public MyRuntimeException(String message) { //手动调用父类的构造方法 super(message); } }
/** * 使用自定义异常 */ public class MyExceptionClass { public static void main(String[] args) { testException1(); testException2(); } private static void testException1() { //【示例代码】自定义受控异常的使用 try { method1(10, 0); } catch (MyCheckedException e) { //必须拦截,拦截后建议给出处理,如果不给出处理,就属于隐藏了该异常 //系统将不给出任何提示,使程序的调试非常困难 System.out.println(e.getMessage()); } } private static void testException2() { method2(10, 0); } /** * 自定义受控异常的使用 * 如果是受控异常必须throws声明,让调用方处理异常 * * @param value1 * @param value2 * @throws MyCheckedException */ private static void method1(int value1, int value2) throws MyCheckedException { if (value2 == 0) { throw new MyCheckedException("方法1,自定义受控异常,除数不能为0!"); } int value3 = value1 / value2; System.out.println(value3); } /** * 【示例代码】,自定义非受控异常的使用 * * @param value1 * @param value2 */ private static void method2(int value1, int value2) { //throws MyRuntimeException { if (value2 == 0) { //抛出非受控异常,方法可以不使用throws进行声明,但也可以显示的声明 throw new MyRuntimeException("方法2,自定义非受控异常,除数不能为0!"); } int value3 = value1 / value2; System.out.println(value3); } }
day9--多线程
并行和并发
- 并行:同一时刻,有多个指令在多个CPU上同时执行。
- 兵法:同一时刻,有多个指令在单个CPU上交替执行。
进程和线程
- 进程:每个进程都有独立的代码和数据空间(进程上下文),进程间的切换会有较大的开销,一个进程包含1--n个线程。任何进程都可以同其他进程一起并发执行
- 线程:进程进一步细化为线程,是一个程序内部的一条执行路径。
实现多线程方式一:继承Thread类
实现步骤
- 创建一个类继承于Thread类
- 重写Thread类的run()方法
- 创建Thread子类的对象
- 通过此对象调用start()方法,启动线程
class Thread1 extends Thread{//步骤1 private String name; public Thread1(String name) { this.name=name; } public void run() {//步骤2 for (int i = 0; i < 5; i++) { System.out.println(name + "运行 : " + i); try { sleep((int) Math.random() * 10); } catch (InterruptedException e) { e.printStackTrace(); } } } } public class Main { public static void main(String[] args) { Thread1 mTh1=new Thread1("A");//步骤3 Thread1 mTh2=new Thread1("B"); mTh1.start();//步骤4 mTh2.start(); } }
不适合多个相同的程序代码的线程去处理同一个资源
为什么要重写run()方法?
因为run()是用来封装被线程执行的代码
run()方法和start()方法的区别?
run():封装线程执行的代码,直接调用,相当于普通方法的调用
start():启动线程;然后由JVM调用此线程的run()方法
Thread.sleep()方法调用目的是不让当前线程独自霸占该进程所获取的CPU资源,以留出一定时间给其他线程执行的机会。
实际上所有的多线程代码执行顺序都是不确定的,每次执行的结果都是随机的。
但是start方法重复调用的话,会出现java.lang.IllegalThreadStateException异常。
实现多线程方式二:实现Runnable接口
- 定义一个类去实现了Runable接口
- 实现类去实现Runnable中的抽象方法:run(),就是重写run方法
- 创建实现类的对象
- 创建Thread类的对象,将步骤3创建的对象作为参数传递到Thread类中的构造器中
- 通过Thread类的对象调用start(),启动线程
具体操作,将一个类实现Runable接口,(插上接口一端)。
另外一端,通过实现类的对象与线程对象通过此Runable接口插上接口实现
class windows implements Runnable{ //步骤1 private String name; public windows(String name) { this.name=name; } @Override public void run() {//步骤2 for (int i = 0; i < 5; i++) { System.out.println(name + "运行 : " + i); try { Thread.sleep((int) Math.random() * 10); } catch (InterruptedException e) { e.printStackTrace(); } } } } public class Main { public static void main(String[] args) { windows w1 = new windows("C");//步骤3 windows w1 = new windows("D"); Thread t1 = new Thread(w1);//步骤4 Thread t2 = new Thread(w1);//同一个w1在继承Thread方式实现多线程就会出错 t1.start(); //步骤5 t2.start(); } }
适合多个相同的程序代码的线程去处理同一个资源
Runnable优势与两种线程方式的比较
- 实现Runnable接口比继承Thread类所具有的优势:
适合多个相同的程序代码的线程去处理同一个资源
可以避免java中的单继承的限制
增加程序的健壮性,代码可以被多个线程共享,代码和数据独立
- 比较创建线程的两种方式:
开发中,优先选择实现Runable接口的方式
原因1:实现的方式没有类的单继承性的局限性
2:实现的方式更适合用来处理多个线程有共享数据的情况
联系:Thread也是实现自Runable,两种方式都需要重写run()方法,将线程要执行的逻辑声明在run中
相关API
- 1.start():
-
- 启动当前线程
- 调用线程中的run方法
- 2.run():通常需要重写Thread类中的此方法,将创建的线程要执行的操作声明在此方法中
- 3.currentThread()静态方法,返回执行当前代码的线程
- 4.getName():获取当前线程的名字
- 5.setName():设置当前线程的名字
- 6.yield():主动释放当前线程的执行权
- 7.join():在线程中插入执行另一个线程,该线程被阻塞,直到插入执行的线程完全执行完毕以后,该线程才继续执行下去
- 8.stop():过时方法。当执行此方法时,强制结束当前线程。
- 9.sleep(long millitime):线程休眠一段时间
- 10.isAlive():判断当前线程是否存活
Thread.currentThread().getName()
实现多线程方式三:实现Callable接口
与runnable对比
与使用runnable方式相比,callable功能更强大些:
runnable重写的run方法不如callaalbe的call方法强大,
call方法可以有返回值
方法可以抛出异常
支持泛型的返回值
需要借助FutureTask类,比如获取返回结果
步骤:
- 定义一个类MyCallable实现Callable接口
- 在MyCallable类中重写call()方法
- 创建MyCallable类的对象
- 创建Future的实现类FutureTask对象,把MyCallable对象作为构造方法的参数
- 创建Thread类的对象,把FutureTask对象作为构造方法的参数
- 启动线程
- 再调用get方法,就可以获取线程结束之后的结果。
使用线程池
线程池存在的意义:
系统创建一个线程的成本是比较高的,因为它涉及到与操作系统交互,当程序中需要创建大量生存期很短暂的线程时,频繁的创建和销毁线程对系统的资源消耗有可能大于业务处理是对系统资源的消耗,这样就有点"舍本逐末"了。针对这一种情况,为了提高性能,我们就可以采用线程池。
线程池在启动的时,会创建大量空闲线程,当我们向线程池提交任务的时,线程池就会启动一个线程来执行该任务。等待任务执行完毕以后,线程并不会死亡,而是再次返回到线程池中称为空闲状 态。等待下一次任务的执行。
使用线程池(批量使用线程)
1.需要创建实现runnable或者callable接口方式的对象
2.创建executorservice线程池
3.将创建好的实现了runnable接口类的对象放入executorService对象的execute方法中执行。
4.关闭线程池
package com.example.paoduantui.Thread; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; /** * 创建线程的方式四:使用线程池(批量使用线程) *1.需要创建实现runnable或者callable接口方式的对象 * 2.创建executorservice线程池 * 3.将创建好的实现了runnable接口类的对象放入executorService对象的execute方法中执行。 * 4.关闭线程池 * * */ class NumberThread implements Runnable{ @Override public void run() { for(int i = 0;i<=100;i++){ if (i % 2 ==0 ) System.out.println(Thread.currentThread().getName()+":"+i); } } } class NumberThread1 implements Runnable{ @Override public void run() { for(int i = 0;i<100; i++){ if(i%2==1){ System.out.println(Thread.currentThread().getName()+":"+i); } } } } public class ThreadPool { public static void main(String[] args){ //创建固定线程个数为十个的线程池 ExecutorService executorService = Executors.newFixedThreadPool(10); //new一个Runnable接口的对象 NumberThread number = new NumberThread(); NumberThread1 number1 = new NumberThread1(); //执行线程,最多十个 executorService.execute(number1); executorService.execute(number);//适合适用于Runnable //executorService.submit();//适合使用于Callable //关闭线程池 executorService.shutdown(); } }
day10--File类和IO流
File类概述
对于File而言,其封装的并不是一个真正存在的文件,仅仅是一个路径名而已.它可以是存在的,也可以是不存
在的.将来是要通过具体的操作把这个路径的内容转换为具体存在的。
public class FileDemo01 { public static void main(String[] args) { //File(String pathname): 通过将给定的路径名字符串转换为抽象路径名来创建新的 File实例 File f1 = new File("E:\\itcast\\java.txt"); System.out.println(f1); //File(String parent, String child): 从父路径名字符串和子路径名字符串创建新的 File实例 File f2 = new File("E:\\itcast","java.txt"); System.out.println(f2); //File(File parent, String child): 从父抽象路径名和子路径名字符串创建新的 File实例 File f3 = new File("E:\\itcast"); File f4 = new File(f3,"java.txt"); System.out.println(f4); } }
File类创建和删除功能
- boolean createNewFile();指定路径不存在该文件时创建文件,返回true 否则false
- boolean mkdir() 当指定的单级文件夹不存在时创建文件夹,返回true 否则false
- boolean mkdirs() 但指定的多级文件夹在某一级文件夹不存在时,创建多级文件夹并返回true 否则false
- boolean delete() 删除文件或者删除单级文件夹
删除文件夹,这个文件夹下面不能有其他的文件和文件夹
package file_demo; import java.io.*; public class demo2 { public static void main(String[] args) throws IOException { //创建一个名为test.txt的文件,如果路径已存在该文件就返回false File file1 = new File("test.txt"); boolean flag = file1.createNewFile(); System.out.println(flag); //创建一个名为b的文件夹 File file2 = new File("b"); boolean flag2 = file2.mkdir(); System.out.println(flag2); File file3 = new File("c/d/e"); boolean d = file3.mkdirs();//这个可以创建c/d/e boolean c = file3.mkdirs(); System.out.println(d); System.out.println(c); File file4 = new File("c.txt"); System.out.println(file4.mkdir()); //删除文件或者删除单级文件夹,删除文件夹,这个文件夹下面不能有其他的文件和文件夹 File file5 = new File("c"); System.out.println(file5.delete()); } }
File类判断功能
- boolean exists() 判断指定路径的文件或文件夹是否为空
- boolean isAbsolute() 判断当前路径是否是绝对路径
- boolean isDirectory() 判断当前的目录是否存在
- boolean isFile() 判断当前的目录是否是一个文件
- boolean isHidden() 判断当前路径是否是一隐藏文件
File类获取功能
- File getAbsoluteFile() 获取文件的绝对路径,返回File对象
- booleanexists() 实例对象代表的文件是否存在
- booleanisFile()实例对象代表的是否是文件
- booleanisAbsolute() 判断是否是绝对路径
- String getAbsolutePath() 获取文件的绝对路径,返回路径的字符串
- String getParent() 获取当前路径的父级路径,以字符串形式返回该父级路径
- String getName() 获取文件或文件夹的名称
- String getPath() 获取File对象中封装的路径
- long lastModified() 以毫秒值返回最后修改时间
- long length() 返回文件的字节数
- String[] list() 获取实例对象代表的文件下的各级文件名和目录名,返回一个字符串数组
public class FileDemo04 { public static void main(String[] args) { //创建一个File对象 File f = new File("myFile\\java.txt"); // public boolean isDirectory():测试此抽象路径名表示的File是否为目录 // public boolean isFile():测试此抽象路径名表示的File是否为文件 // public boolean exists():测试此抽象路径名表示的File是否存在 System.out.println(f.isDirectory()); System.out.println(f.isFile()); System.out.println(f.exists()); // public String getAbsolutePath():返回此抽象路径名的绝对路径名字符串 // public String getPath():将此抽象路径名转换为路径名字符串 // public String getName():返回由此抽象路径名表示的文件或目录的名称 System.out.println(f.getAbsolutePath()); System.out.println(f.getPath()); System.out.println(f.getName()); System.out.println("‐‐‐‐‐‐‐‐"); // public File[] listFiles():返回此抽象路径名表示的目录中的文件和目录的File对象数组 File f2 = new File("E:\\itcast"); File[] fileArray = f2.listFiles(); for(File file : fileArray) { // System.out.println(file); // System.out.println(file.getName()); if(file.isFile()) { System.out.println(file.getName()); } } } }
流和IO流
流:数据在设备间的流向
IO流:输入/输出流
IO流分类:
按数据流向:
输入流:读数据(键盘数据读到内存)
输出流:写数据(内存数据输出到其他地方)
按数据类型:
字节流:字节输入流,字节输出流
字符流:字符输入流,字符输出流
使用场景:
- 如果操作的是纯文本文件,优先使用字符流
- 如果操作的是图片、视频、音频等二进制文件,优先使用字节流
- 如果不确定文件类型,优先使用字节流.字节流是万能的流
字节流写数据步骤
- 创建字节输出流对象(调用系统功能创建了文件,创建字节输出流对象,让字节输出流对象指向文件)
- 调用字节输出流对象的写数据方法
- 释放资源(关闭此文件输出流并释放与此流相关联的任何系统资源)
public class FileOutputStreamDemo01 { public static void main(String[] args) throws IOException { //创建字节输出流对象 /* 注意点: 1.如果文件不存在,会帮我们创建 2.如果文件存在,会把文件清空 */ //FileOutputStream(String name):创建文件输出流以指定的名称写入文件 FileOutputStream fos = new FileOutputStream("myByteStream\\fos.txt"); //void write(int b):将指定的字节写入此文件输出流 fos.write(97); // fos.write(57); // fos.write(55); //最后都要释放资源 //void close():关闭此文件输出流并释放与此流相关联的任何系统资源。 fos.close(); } }
public class FileOutputStreamDemo02 { public static void main(String[] args) throws IOException { //FileOutputStream(String name):创建文件输出流以指定的名称写入文件 FileOutputStream fos = new FileOutputStream("myByteStream\\fos.txt"); //FileOutputStream(File file):创建文件输出流以写入由指定的 File对象表示的文件 // FileOutputStream fos = new FileOutputStream(new File("myByteStream\\fos.txt")); //void write(int b):将指定的字节写入此文件输出流 // fos.write(97); // fos.write(98); // fos.write(99); // fos.write(100); // fos.write(101); // void write(byte[] b):将 b.length字节从指定的字节数组写入此文件输出流 // byte[] bys = {97, 98, 99, 100, 101}; //byte[] getBytes():返回字符串对应的字节数组 byte[] bys = "abcde".getBytes(); // fos.write(bys); //void write(byte[] b, int off, int len):将 len字节从指定的字节数组开始,从偏移量off开 始写入此文件输出流 // fos.write(bys,0,bys.length); fos.write(bys,1,3); //释放资源 fos.close(); } }
- 字节流写数据如何实现追加写入
public FileOutputStream(String name,boolean append)
创建文件输出流以指定的名称写入文件。如果第二个参数为true ,则字节将写入文件的末尾而不是开头示例代码。
public class FileOutputStreamDemo03 { public static void main(String[] args) throws IOException { //创建字节输出流对象 // FileOutputStream fos = new FileOutputStream("myByteStream\\fos.txt"); FileOutputStream fos = new FileOutputStream("myByteStream\\fos.txt",true); //写数据 for (int i = 0; i < 10; i++) { fos.write("hello".getBytes()); fos.write("\r\n".getBytes()); } //释放资源 fos.close(); } }
字节流写数据加异常处理【应用】
字节流读数据
字节输入流读取数据的步骤
- 创建字节输入流对象
FileInputStream fis = new FileInputStream("myByteStream\\fos.txt");
- 调用字节输入流对象的读数据方法
int by = fis.read();
- 释放资源
fis.close();
字节缓冲流
字符流
对象序列化流
day11--网络编程之TCP
服务器端实现步骤:
- 创建ServerSocket对象
- 监听-----Socket s = ss.accept();
- 获取输入流,读数据
public class ServerDemo { public static void main(String[] args) throws IOException { //创建服务器端的Socket对象(ServerSocket) //ServerSocket(int port) 创建绑定到指定端口的服务器套接字 ServerSocket ss = new ServerSocket(10000); //Socket accept() 侦听要连接到此套接字并接受它 Socket s = ss.accept(); //获取输入流,读数据,并把数据显示在控制台 InputStream is = s.getInputStream(); byte[] bys = new byte[1024]; int len = is.read(bys); String data = new String(bys,0,len); System.out.println("数据是:" + data); //释放资源 s.close(); ss.close(); } }
public class ClientDemo { public static void main(String[] args) throws IOException { //创建客户端的Socket对象(Socket) //Socket(String host, int port) 创建流套接字并将其连接到指定主机上的指定端 口号 Socket s = new Socket("127.0.0.1",10000); //获取输出流,写数据 //OutputStream getOutputStream() 返回此套接字的输出流 OutputStream os = s.getOutputStream(); os.write("hello,tcp,我来了".getBytes()); //释放资源 s.close(); } }
day12---注解
作用:对程序进行标注和解释。
基础引入
public class Zi extends Fu{ @Override//告诉编译器,该方法重写类父类方法 public void show() { System.out.println("子类的方法"); } @Deprecated //过时的方法 public void methos(){ System.out.println("method......"); } @SuppressWarnings(value = "all")//压制本方法中的所有警告 public void function(){ int a = 10; int b = 20; } }
自定义注解
格式:
public @interface 注解名称{ public 属性类型 属性名 ()default 默认值; }
public @interface Anno1 { //定义基本类型的属性 int a () default 23; //定义一个String类型的 public String name(); //定义一个class类型的属性 public Class clazz() default Anno2.class; //定义一个注解类型的属性 public Anno2 ann0() default @Anno2; //定义一个枚举类型的 public Season season() default Season.SPRING; // 一维数组 public int[] arr() default {1,2,3,4,5}; // 枚举数组 public Season[] seasons() default {Season.SPRING,Season.SUMMER}; }
//在使用注解的时候,如果注解里面的属性没有默认值 //那么我们就需要手动给出注解属性的设置值 @Anno1(name = "itheima") //该注解只有String的没给默认值 public class AnnoDemo { }
注解---特殊属性
value
后期在使用注解的时候,如果我们只需要给注解的value属性赋值,那么value就可以省略。
@Anno1("abc") public class AnnoDemo { }
自定义Test注解
public class UseTest { public void show(){ System.out.println("UseTest....show...."); } @Test public void methos(){ System.out.println("UseTest....methos...."); } @Test public void function(){ System.out.println("UseTest....function...."); } }
@Retention(value = RetentionPolicy.RUNTIME) public @interface Test { }
public class AnnoDemo1 { public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, InvocationTargetException { //1.通过反射获取UseTest类的字节码文件对象 Class<?> clazz = Class.forName("zhujie.UseTest"); //4.创建对象 UseTest useTest = (UseTest) clazz.newInstance(); //2.通过反射获取这个类中所有方法对象 Method[] methods = clazz.getDeclaredMethods(); //3.遍历数组,得到每一个方法对象 for (Method method : methods) { //method依次标识每一个方法对象 // isAnnotationPresent(Class<? extends Annotation> annotationClass) //判断当前方法上是否有指定注解 //参数:注解的字节码文件对象 //返回值:布尔结果 if(method.isAnnotationPresent(Test.class)){ method.invoke(useTest);//运行 } } } }
元注解
描述注解的注解,就是写在注解上的注解。
元注解名 | 说明 |
@Target | 指定了注解能在哪里使用 |
@Retention | 可以理解为保留时间(生命周期) |
@Inherited | 表示修饰的自定义注解可以被子类继承 |
@Documented | 表示该自定义注解,会出现在API文档里面。 |
@Target({ElementType.FIELD,ElementType.TYPE,ElementType.METHOD}) 用的位置(成员变量,类,方法) @Retention(RetentionPolicy.RUNTIME) //指定该注解的存活时间 //@Inherited //指定该注解可以被继承 public @interface Anno { } @Anno public class Person { } public class Student extends Person { public void show(){ System.out.println("student.......show.........."); } } public class StudentDemo { //指定注解使 public static void main(String[] args) throws ClassNotFoundException { //获取到Student类的字节码文件对象 Class clazz = Class.forName("com.itheima.myanno4.Student"); //获取注解。 boolean result = clazz.isAnnotationPresent(Anno.class); System.out.println(result); } }