学习方法
先只通过代码写注释,再只通过注释写代码
先解决问题,再发现更多方案,最后选择最优
计算机基础
快捷键
ctrl d
ctrl y
ctrl shift ↑ ↓
ctrl d
alt 可以区域复制,批量输入
数据类型
模块可以导入和删除
包可以用来区分重名的类
‘ ’ 里面有且只能有一个字符
“ ”随意
可以输出 true false ,但不能输出null
.java
命名规范
类 接口 每个单词首字母大写
HelloWord
变量 方法 第二个单词开始首字母大写
zhangNameAge
常量 全部大写,单词用_隔开
MAX_VALUE
包 全部小写 多级包用 . 隔开
cn.itcast
类型转换
自动类型转换
double 8个字节
int 4个字节
byte 1个字节
int + byte =int(自动转换为4个字节)
byte,short,char->int->long–>float->double
强制类型转换
新建类 ctrl alt insert
类型兼容的情况下
数据类型 变量名 = (目标数据类型) 初始化值;
double d = 10;
int a = (int)d;
常量相加,直接运算,结果不能超过数据类型范围
byte b1 = 3;
byte b2 = 4;
byte b3 = 3 + 4 ; ✔
变量相加,自动提升数据类型,再进行运算,防止数据类型不够用
byte b4 =( byte )( b1 + b2);变量 + 变量 ;
byte b5 =( byte )( b1 +4);变量 + 常量 ;
ASCII码表
sout(’ 字符 ‘ + 0);
赋值运算符
+= -= *= /= %= (取余)
b += a ( b = b +a )
关系运算符
== 判断是否等
!= 判断是否不等
> 判断
>= 判断
< 判断
<= 判断
成立为true,不成立为false
逻辑运算符
& 与 不能有假
| 或 有真就行
! 非 取反
^ 逻辑异或,a^b,异同的意思,同为false
短路逻辑运算符
&& 双与 前面出现false,后面不执行
|| 双或 前面出现true,后面不执行
三元运算符
类似if else循环
(关系表达式) ? 表达式1 : 表达式2 ;
关系表达式为true,则执行 表达式1
否则执行 表达式2
基础语法
方法
例如: 让我们获取元素10和20的最大值, 我们可以通过if语句或者三元运算符实现, 如果再让我们获取22和11之间的最大值, 我们还需要把刚才的逻辑代码在写一次. 这样做很繁琐. 针对于这种情况, 我们就可以把获取两个整数最大值的逻辑代码 封装 到方法中, 当我们需要比较的时候, 直接调用方法就可以了. 这样做, 非常方便.
定义格式
修饰符 返回值的数据类型 方法名(参数类型 参数名1, 参数类型 参数名2) { //这里可以写多个参数
//方法体;
return // 具体的返回值;
}
public static void main (String[] args) {
}
}
格式解释
-
修饰符: 目前记住这里是固定格式public static
-
返回值的数据类型: 用于限定返回值的数据类型的.
注意:
返回值的数据类型是int类型, 则说明该方法只能返回int类型的整数.
如果方法没有具体的返回值, 则返回值的数据类型要用void来修饰.
-
方法名: 方便我们调用方法.
-
参数类型: 用于限定调用方法时传入的数据的数据类型.
例如: 参数类型是String类型, 说明我们调用方法时, 只能传入字符串.
-
参数名: 用于接收调用方法时传入的数据的变量.
-
方法体: 完成特定功能的代码.
-
return 返回值: 用来结束方法的, 并把返回值返回给调用者.
解释: 如果方法 没有明确的返回值, 则return关键字可以省略不写.
方法重载
同一个类中, 出现方法名相同, 但是**参数列表不同 **(个数或类型不同) 的两个或以上的方法时称为方法重载
使用场景
定义方法compare(), 用来比较数据是否相等.
- 要求:兼容所有的整数类型, 即(byte, short, int, long)
示例:
public class MethodDemo01 {
public static void main(String[] args) {
//定义不同数据类型的变量
byte a = 10;
byte b = 20;
short c = 10;
short d = 20;
int e = 10;
int f = 10;
long g = 10;
long h = 20;
// 调用
System.out.println(compare(a, b));
System.out.println(compare(c, d));
System.out.println(compare(e, f));
System.out.println(compare(g, h));
}
// 两个byte类型
public static boolean compare(byte a, byte b) {
System.out.println("byte");
return a == b;
}
// 两个short类型的
public static boolean compare(short a, short b) {
System.out.println("short");
return a == b;
}
// 两个int类型的
public static boolean compare(int a, int b) {
System.out.println("int");
return a == b;
}
// 两个long类型的
public static boolean compare(long a, long b) {
System.out.println("long");
return a == b;
}
}
注意事项
方法与方法之间是平级关系, 不能嵌套定义.
方法必须先创建才可以使用, 该过程称为: 方法定义.
方法自身不会直接运行, 而是需要我们手动调用方法后, 它才会执行, 该过程称为方法调用.
方法的功能越单一越好.
定义方法的时候写在参数列表中的参数, 都是: 形参.
形参: 形容调用方法的时候, 需要传入什么类型的参数.
调用方法的时候, 传入的具体的值 (变量或者常量都可以), 叫实参.
实参: 调用方法时, 实际参与运算的数据.
方法调用
三个明确
定义方法时, 要做到三个明确
- 方法名, 小驼峰命名法, 要见名知意
- 方法的参数列表: 需要给方法什么数据
- 返回值类型: 方法会返回给我们一个什么类型的数据.
键盘录入
Scanner sc = new Scanner(System.in);
int a =sc.nextint();
if
如果if的控制(执行)语句只有一行代码,不用大括号
if(a==0)
a++;
else
a--;
switch
Scanner sc = new Scanner(System.in);
System.out.println("请录入一个月份: ");
int month = sc.nextInt();
switch (month) {
case 12:
System.out.println("冬季");
break;
case 1:
System.out.println("冬季");
break;
……………………
default:
System.out.println("没有这样的日期");
break;
case穿透
case的后面break不写,不会在判断下一个case的值,直到遇到break,或者switch结束。
使用场景,两个case,break一个结果
switch(month) {
case 12:
case 1:
case 2:
System.out.println("冬季");
break;
case 3:
case 4:
case 5:
System.out.println("春季");
break;
default:
System.out.println("没有这样的日期");
break;
Default语句不放最后也行,任意位置,放最后规范
最后一个break和第一个右括号都可以结束语句,所以break能省略
for循环
固定循环次数
for(int i = 0;i < 10 ; i++)
for( 初始化条件1 ; 判断条件2 ;控制条件3 ){ 循环体 ;}
while循环
while(判断条件2) { //循环体3; //控制条件4;} while (i <= 100) { if (i % 2 == 0) sum += i;//循环体----循环代入i i++;//控制条件----控制i值 }
Do While
int i = 1;do{ System.out.println("Hello World! " + i); //循环体,循环代入 i++; //控制条件,控制i值 }while(i <= 10); //判断条件,判断跳出条件
三种循环之间的区别
do.while循环和其他两个循环之间的区别
-
do.while循环是先执行一次, 后判断.
-
而其他两个循环都是先执行判断条件, 然后决定是否执行循环体.
for循环和其他两个循环之间的区别
-
for循环执行结束后, 初始化条件就不能继续使用了.
-
而其他两个循环执行结束后, 初始化条件还可以继续使用.
总结:do-while 先执行操作,再判断条件,for 循环结束后,初始化条件不能继续用
Break
for(int i = 1; i <= 10 ; i++) { if(i == 5) break; //if为true,break for循环 System.out.println("Hello World!" + i); } System.out.println("end");
continue
for (int i = 1; i <= 10; i++) { if (i % 3 == 0)//if为true,结束本次循环 continue;// if为false, continue System.out.println(i); } System.out.println("end");
参数传递
数组
数组, 就是一种容器
数组用来存储多个同类型元素
创建数组:
//动态初始化
int[] arr1 = new int[3]; //推荐.
// int arr2[] = new int[3];
//静态
//直接传入存储数据`11, 22, 33`, 由系统指定长度.
// int[] arr3 = new int[]{11, 22, 33};
int[] arr4 = {11, 22, 33};
//数组索引
System.out.println(arr[1]); //打印结果是: 22
arr[1] = 222;
内存解释
内存是计算机中的重要原件,也是临时存储区域,作用是运行程序。我们编写的程序是存放在硬盘中的,在硬盘中的程序是不会运行的,必须放进内存中才能运行,运行完毕后 会清空内存。
即: Java虚拟机要运行程序,必须要对内存进行空间的分配和管理。为了提高运算效率,就对空间进行了不同区域的划分,因为每一片区域都有特定的处理数据方式和内存管理方式。
JVM的内存划分
栈: 存储局部变量以及所有代码执行的.
局部变量: 指的是定义在方法中, 或者方法声明上的变量.
特点: 先进后出.
堆: 存储所有new出来的内容(即: 对象).
特点: 堆中的内容会在不确定的时间, 被GC回收.
方法区: 存储字节码文件的.
字节码文件: 指的是后缀名为.class的文件.
本地方法区:
和系统相关, 了解即可.
寄存器
和CPU相关, 了解即可.
打印数据地址
public class ArrayDemo03 {
public static void main(String[] args) {
int[] arr = new int[3];
System.out.println(arr[0]); //打印数组中的第一个元素, 值为: 0
System.out.println(arr); //[I@1540e19d
}
}
其中 [I@1540e19d是 arr 数组的地址值 ,
调用方法
无参无返回值
当一些代码被反复使用时,可以把它们提取出来,放(封装)到一个方法里,以方法的形式来使用这些代码-----可以提高代码的复用性, 方便维护程序.
-
格式
public static void printHello() { System.out.println("Hello World!); }
-
调用
printHello()
有参无返回值
调用方法时, 我们需要传入具体的参数, 但是方法执行完毕后, 并不会给我们返回具体的结果.
- 格式
public static void 方法名(参数类型 参数名1, 参数类型 参数名2) { //这里可以写多个参数
//方法体;
}
- 调用
方法名(参数值1, 参数值2);
无参有返回值
调用方法时, 我们不需要传入具体的参数, 但是方法执行完毕后, 会给我们返回具体的结果.
- 格式
public static int sum() {
Scanner
//或者
//静态参数
return sum;
}
-
调用格式
- 直接调用, 无意义
sum();
- 输出调用,演示用
System.out.println(sum());
- 赋值调用, 实际开发中推荐使用
int value = sum();
有参有返回值
调用方法时, 我们不仅需要传入具体的参数, 方法执行完毕后, 还会给我们返回具体的结果
- 格式
public static 返回值的数据类型 方法名(参数类型 参数1, 参数类型 参数2) {
//方法体;
return 具体的返回值;
}
-
调用
-
直接调用
方法名(参数值1, 参数值2);
-
输出调用
System.out.println(方法名());
-
赋值调用
数据类型 变量名 = 方法名();
-
参数传递
定义方法时,参数列表中的变量,我们称为形式参数.
调用方法时,传入给方法的数值,我们称为实际参数.
基础知识补充
基本类型的变量保存原始值,即它代表的值就是数值本身, 原始值一般对应在内存上的栈区(存储局部变量以及所有代码执行的);基本类型包括: byte
, short
, int
, long
, char
, float
, double
, boolean
这八大基本数据类型
引用类型的变量保存引用值,引用值指向内存空间的地址。代表了某个对象的引用,而不是对象本身。对象本身存放在这个引用值所表示的地址的位置。被引用的对象对应内存上的堆内存区。引用类型包括: 类类型
, 接口类型
和 数组
。
值传递:实际参数把它的值传递给对应的形式参数,函数接收的是原始值的一个拷贝, 此时内存中存在两个相等的基本类型,即实际参数和形式参数,后面方法中的操作都是对形参这个值的修改,不影响实际参数的值。
引用传递:也称为地址传递、址传递。方法调用时,实际参数的引用(地址,而不是参数的值)被传递给方法中相对应的形式参数,函数接收的是原始值的内存地址。在方法执行中,形参和实参内容相同,指向同一块内存地址,方法执行中对引用的操作将会影响到实际对象。
一般说的改变一个String变量,其实并不是改变的这个String本身,而是用一个新的String去替换掉原来的,原来的String本身并没有变
通常 基本类型 和 String 传递是值传递,形参的改变不会影响实参的改变
基本类型和引用类型的区别:基本数据类型在声明时系统就给它分配空间;而引用数据类型不同,它声明时只给变量分配了引用空间,而不分配数据空间。
总结:
基本类型通过值传递方法传递实参的原始值,函数接收到原始值cpoy为形参,方法体只能修改形参,byte
, short
, int
, long
, char
, float
, double
, boolean
这**八大基本数据类型 **和 String。
引用类型通过引用传递方法传递内存空间的地址,对应内存上的堆内存区。引用类型包括: 类类型, 接口类型 和 数组
形参是基本类型
//观察下述代码, 打印结果是什么呢? public class MethodDemo02 { public static void main(String[] args) { int number = 100; System.out.println("调用change方法前:" + number); change(number); //实参. System.out.println("调用change方法后:" + number); } public static void change(int number) { //形参. number = 200; }}
**记忆: 基本类型作为参数时, 形参的改变对实参没有任何影响. **
形参是引用类型
public class MethodDemo03 { public static void main(String[] args) { int[] arr = {10, 20, 30}; System.out.println("调用change方法前:" + arr[1]); change(arr); System.out.println("调用change方法后:" + arr[1]); } public static void change(int[] arr) { arr[1] = 200; }}
记忆: 引用类型作为参数时, 形参的改变直接影响实参.
Debug
步骤: 1. 加断点, 哪里不会点哪里. 2. 运行加了断点的程序, 注意: 不要选择run, 要选择debug(就是小蜘蛛) 3. 开始调试后, 看哪里呢? Debugger: 看代码执行到哪里了. Console: 控制台, 就是查看程序运行结果的. Variable: 就是查看 变量的变化过程的. 4. 如何进行下一步? F7: 逐过程调试 F8: 逐行调试 F9: 逐断点调试 5. 如何删除断点? 方式1: 一个一个删除. 方式2: 批量删除. //选择breakpoints(双红点), 移除断点即可.
面向对象
面试标准回答
概述 思想特点 举例 总结
c面向过程
java面向对象,表示现实世界,万物皆可对象化
类
举例
类是学生**,抽象概念,类的实例化对象,例如:成员变量:张三 23 岁,成员方法:给 张三 发消息
学生类
//学生类(类:抽象概念 看不见 )
public class Student{
//成员变量(属性:描述事物外在特征)
//先写到 类中, 方法外, 而且成员变量有默认值
String name; //姓名
int age; //年龄
//成员方法(行为:事物能够做什么)
//先不写static
public void study() {//学习的方法
System.out.println("键盘敲烂, 月薪过万!...");
}
public void eat() {//吃饭的方法
System.out.println("学习饿了要吃饭!...");
}
}
操作学生类
调用
public class StudentTest{
public static void main(String[] args) {
//1. 创建学生类的对象.
Student s = new Student();
//2. 访问成员变量.
System.out.println(s.name);//输出null
System.out.println(s.age);//输出0
//3. 给成员变量赋值.
s.name = "张三";
s.age = 23;
//4. 访问成员变量.
//通过 对象名.成员变量 来使用类中的成员
System.out.println(s.name);
System.out.println(s.age);
//5. 访问成员方法.
//通过 对象名.成员方法(参数1, 参数2) 来使用类中的成员
s.study();
s.eat();
}
}
成员变量和成员方法
package com.itheima.demo02_phone;
//案例: 定义手机类, 用来描述手机的(属性, 行为)
//像这样的用来描述事物的类叫: 实体类, 也叫: JavaBean类, POJO类.
public class Phone {
// 属性: 也叫成员变量, 就是用来描述事物的外在特征的(即: 名词)
String brand; //品牌
int price; //价格
String color; //颜色
// 成员方法-行为: 打电话(call), 发短信(sendMessage)
//打电话
public void call(String name) { //夯哥
System.out.println("给" + name + "打电话!...");
}
//发短信
public void sendMessage(String name) {
System.out.println("给" + name + "发短信!...");
}
成员变量和局部变量
记忆
-
成员变量: 指的是定义在类中, 方法外的变量.
-
局部变量: 指的是定义在方法中, 或者方法声明上的变量.
区别:
定义位置不同.
-
成员变量: 定义在类中, 方法外.
-
局部变量: 定义在方法中, 或者方法声明上.
在内存中的存储位置不同.
-
成员变量: 存储在堆内存.
-
局部变量: 存储在栈内存.
生命周期不同.
-
成员变量: 随着对象的创建而存在, 随着对象的消失而消失.
-
局部变量: 随着方法的调用而存在, 随着方法的调用完毕而消失.
初始化值不同.
-
成员变量: 有默认值.
-
局部变量: 没有默认值, 必须先定义, 再赋值, 然后才能使用.
public class VariableDemo{
int x;//不需默认值
public void show() {
int y = 10;//默认值,在方法内有效
System.out.println(x);
System.out.println(y);
}
}
封装
Private
private修饰的内容只能在本类中使用
封装就是隐藏对象的属性和实现细节, 仅对外提供一个公共的访问方式(get set)
package com.itheima.demo04_student;
//定义学生类(JavaBean类, 实体类, POJO类)
public class Student {
//属性, 也叫成员变量, 即: 名词.
String name; //姓名.
private int age; //年龄
//针对于被private修饰的变量, 需要对外提供一个公共的访问方式.
//设置变量age的值.
public void setAge(int a) {
//针对于用户录入的值a, 我们可以判断
if (a >= 0 && a <= 200) {
//合法年龄, 就设置.
age = a;
}
}
//获取变量age的值.
public int getAge() {
return age;
}
//行为, 也叫成员方法, 即: 动词.
public void show() {
System.out.println(name + "..." + age);
}
}
问题:用户直接范围age,任意设置,比如**年龄设置为负数
封装Get-Set
如果不想某些内容被直接访问,可以用private修饰,再**封装一个访问方法(Get-Set过滤条件)**来访问
//案例: 学生类的测试类
package com.itheima.demo04_student;
public class StudentTest {
public static void main(String[] args) {
//1. 创建学生类的对象.
Student s = new Student();
//2. 设置成员变量值.
s.name = "刘亦菲";
//s.age = -33;
//以下为: 采用封装后的代码.
//设置年龄
s.setAge(-33);
//获取年龄
System.out.println(s.getAge());
//3. 打印成员变量值.
/*System.out.println(s.name);
System.out.println(s.age);*/
//System.out.println(s); //打印地址值.
s.show();
}
}
意义:防止用户直接访问
继承
This
哪个对象调用了方法,就用继承对象的变量, 解决局部变量和成员变量重名问题
记忆
使用变量的 “就近原则”: 局部位置有就使用, 没有就去本类的成员位置找
public class Student {
//成员变量
int x = 10;
public void method() {
//局部变量
int x = 20;
System.out.println(this.x); //10
System.out.println(x); //20
}
}
student 对象调用了 method 方法
方法里重名的 this.x 就从 继承 student 类里 的 x 的值
Student s = new Student();
//调用Student#method()
s.method();
Extends
多个类有相同属性行为,将这些内容集中为一个类,其他类使用时 继承 这个类即可
public class 类A extends 类B { //子A 承 父业B}
开发原则: 高内聚, 低耦合.
内聚: 指的是类自己独立完成某些事情的能力,
耦合: 指的是类与类之间的关系.
- 即 : 提高子类的功能,尽量不继承父类
例:
//人类, 在这里充当的角色是父类.public class Person { //ctrl + 字母H: 查看类的继承关系树. //属性 private String name; private int age; //构造方法, 如果我们不写, 系统会默认加一个: 空参构造. //getXxx(), setXxx() public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } //行为 public void eat() { System.out.println("人要吃饭"); } public void sleep() { System.out.println("人要睡觉"); }}
//案例: 学生类public class Student extends Person { //学生类独有的功能: 学习 public void study() { System.out.println("好好学习, 天天向上!"); }}
//案例: 老师类public class Teacher extends Person { //老师类独有的功能: 讲课 public void teach() { System.out.println("老师要讲课!"); }}
测试:
//1. 测试老师类 Teacher t = new Teacher(); //属性 //从Person类继承. //方法 t.eat(); //从Person类继承. t.sleep(); //从Person类继承. t.teach(); //本类的独有功能.
只能继承单个,不能继承多个,可以多层继承,爷>子>孙……
Super
就近原则:
局部位置有**(age)**就使用,
没有就去本类的**(this.age)**成员位置找,有就使用,
再没有就去父类的**(super.age)**成员位置找, 有就使用, 没有就报错.
public class Son extends Father{ int age = 20; //本类的成员变量. public void show() { int age = 10; //局部变量 System.out.println(age); //局部10 System.out.println(this.age); //本类20 System.out.println(super.age); //父类30 }}
继承中构造方法
访问参数时
子类空参 Son() 访问父类 Super() 空参
子类带参Son(name) 访问父类super(name) 带参
public class Son extends Father{ public Son() { super(); //子类的空参访问父类的空参 System.out.println("Son类的 空参构造, 用来初始化子类内容"); } public Son(String name) { super(name); //子类的带参访问父类的带参. //this(); System.out.println("Son类的 带参构造, 用来初始化子类内容"); }}
继承中成员方法
调用成员方法遵循"就近原则"
先调用本类,本类中没有自动去父类,父类没有则报错
调用
Son s = new Son(); //2. 调用Son类中的方法. s.method(); //Son show... s.show(); //Son method...
子类
public class Son extends Father{ public void show() { System.out.println("Son show..."); } public void method() { System.out.println("Son method..."); }}
父类
public class Father { public void show() { System.out.println("Father show..."); } public void method() { System.out.println("Father method..."); }}
方法重写
注解:@Override
要求:
-
子类父类方法的名字返回值类型一摸一样
-
父类私有(private)的方法子类无法访问,更无法重写
-
子类重写父类方法时, 访问权限不低于父类
private < 默认 (什么都不写)< protected < public
通常,只有局部变量private,父类一般都是public
public class NewPhone extends Phone{ //重写父类Phone#call()方法 //在打电话的时候, 增加播放彩铃功能. @Override public void call(String name) { //调用父类的call()方法, 实现基础打电话功能. super.call(name); //加入新的需求: 播放彩铃 System.out.println("播放彩铃..."); }
多态
同一个事物在不同时刻表现出来的不同状态,形态–父类的多个子类形态
前提
-
继承关系
-
方法重写
-
父类引用指向子类对象
Animal an = new Cat();
使用(左)父类的成员变量,(右)子类的成员方法
因为,方法重写了,但变量没有
但是new的父类对象无法调用子类没有重写的方法,所以使用向下转型
Cat c = (Cat)an;
Animal an = new Cat(); //编译看左 运行看右//父类变量--子类方法 an.eat(); //调用猫类中独有的 catchMouse()功能. an.catchMouse(); //报错 //多态版的 猫类对象 -> Cat类型的猫类对象(多态转普通对象) Cat c = (Cat)an; //引用类型的: 向下转型, 即: 大 -> 小. c.catchMouse(); //新的普通对象可以使用子类没有重写的方法
向上转型-向下转型
//向上转型 和 向下转型都是针对于 引用类型来讲的 // 向上转型: cat() -> Animal() Animal an = new Cat(); //类似于: 基本类型的隐式类型转换, double d = 10; //向下转型: Animal()-cat() -> cat() Cat c = (Cat)an; //类似于: 引用类型的强制类型转换, 即: int a = (int)d;
多态访问成员方法
开发常用
//cat重写animal的eatpublic static void show(Animal an) { //Animal an = new Cat(); //编译看左Animal an, 运行看右cat.eat(). an.eat();} Cat c = new Cat(); show(c); //猫吃鱼. System.out.println("-------------------");
Instanceof
多态访问子类重写的成员方法的同时
用来识别归属子类,调用该子类独有的成员方法
public static void show(Animal an) { //Animal an = new Dog(); an.eat(); //判断传入的是否是猫类 if (an instanceof Cat) { //说明是猫类对象, 向下转型, 调用猫类方法 Cat c = (Cat)an; c.catchMouse(); } else if(an instanceof Dog) { //说明是狗类对象, 向下转型, 调用狗类方法 Dog d = (Dog)an; d.lookHome(); }}
Final
锁死 类,变量,方法
-
修饰类: 不能被继承, 但是可以继承其他类.
-
修饰变量: 是个常量(Int类), 只能被赋值一次.
final int a = 10;//a = 20; //这样写会报错.
-
修饰方法: 不能被子类重写.
面试题
- final修饰**基本类型的常量(final int a = 10)和 修饰引用类型的数据(final Father f = new Father() )**有什么区别?
final int a = 10;//a = 20; //这样写会报错.//如果修饰的引用类型的常量: //是地址值不能发生变化 //但是该对象的属性值可以发生变化.final Father f = new Father();//f = new Father(); //这样写会报错, 如果修饰的引用类型的常量: 是地址值不能发生变化,f.name = "刘亦菲";f.name = "高圆圆";System.out.println(f.name);
- final-finally-finalize 三个关键字的区别
Static
表示静态的意思, 可以修饰成员变量, 成员方法
作用(特点):
-
随着类的加载而加载.
-
优先于对象存在.
-
被static修饰的内容, 能被该类下所有的对象所共享.
-
静态内容可以被 类名. 的形式直接调用.
Student.show2();
静态方法访问特点
访问特点:
静态方法只能访问静态的成员变量和静态的成员方法.
即: 静态只能访问静态
注意事项:
1.在静态方法中, 是没有this, super关键字的.
2.因为静态的内容是随着类的加载而加载, 而this和super是随着对象的创建而存在.
即: 先进内存的, 不能访问后进内存的.
Student s = new Student(); s.show1(); s.show2(); // 不报错, 不推荐. //结论: 非静态方法可以访问所有成员(非静态变量和方法, 静态变量和方法) Student.show2(); //静态方法只能访问静态成员
public class Student { String name = "刘亦菲"; //非静态成员变量 static int age = 33; //静态的成员变量 public void show1() { } public static void show2() { System.out.println("show2方法 静态方法"); }}
抽象类
特点
-
抽象类和抽象方法都用 **abstract ** 修饰
-
抽象方法没有方法体,用abstract修饰
//抽象方法public abstract void eat();
-
有抽象方法的类一定是抽象类
//父类, 动物类public abstract class Animal { //1.类中有一个抽象方法eat(), 还有一个非抽象方法sleep(). public abstract void eat(); public void sleep() { System.out.println("动物要睡!"); }}
-
创建抽象类多态, 来完成抽象类的初始化.
Animal an = new Cat();
-
普通类继承抽象类 必须重写父类所有的抽象方法.
public class Cat extends Animal{ @Override public void eat() { System.out.println("猫吃鱼!"); }}
-
抽象类继承抽象类, 不用重写父类的抽象方法.
-
小技巧: final 一般要结合 static, public, 或者private 一起使用.
static final String COUNTRY = "中国"; //国籍
-
思考: 既然抽象类不能实例化, 那要构造方法有什么用?
答: 用于子类对象访问父类数据前, 对父类数据进行初始化 也就是:可以使用抽象类多态初始化父类变量和方法
Person p = new Student();
- 思考: 抽象类中的抽象方法和非抽象方法的作用是什么?
抽象方法: 强制子类完成某些事情(作为模板重写)
非抽象方法: 让子类可以直接使用
接口
特点
-
接口用 interface 修饰.
-
类和接口之间是实现关系, 用**implements(实现)**关键字表示.
-
接口不能实例化.
那接口如何实例化呢?
可以通过多态的方式, 创建其子类对象, 来完成接口的实例化. 这也叫: 接口多态Jumpping jp = new Cat();
-
接口的子类:
1.如果是普通类, 则必须重写父接口中所有的抽象方法.
2.如果是抽象类, 则可以不用重写父接口中的抽象方法.
-
接口中有且只能有常量或者抽象方法.
变量的默认修饰符: public static final
方法的默认修饰符: public abstract -
接口中是没有构造方法的, 因为它主要是用来对类的功能进行: 扩展, 升级, 延伸.-----也就是,扩展定义成员方法的模板
//定义接口, 扩展说英语的功能public interface SpeakEnglish { void speak();}
-
JDK1.8的时候, 接口中加入了两个新成员:
支持静态方法
支持默认方法, 必须用default修饰.
面试
抽象类和接口的区别
-
成员
- 抽象类 :变量 ,常量,构造方法,抽象方法,非抽象方法
- 接口:常量,抽象方法,JDK.8的静态方法,默认方法
-
关系
-
类与类间:只能多层单个继承
-
类与接口间:一个类可在继承一个类的同时可实现一个或多个接口
// 子类 继承 一个亲爹 实现 多个干爹public class Cat extends Animal implements A,B,C{}
-
接口与接口间:一或多
public interface B extends C{ public abstract void methodB();}
-
-
设计理念
- 抽象类:定义功能模板
- 接口:扩展功能模板
包
对类进行分类管理,按照功能或模块划分
注意
-
java.lang 包下的类可以直接使用, 无需导入
-
用public修饰的类叫: 公共类, 也叫顶级类, 在一个.java文件中, 顶级类只能有一个, 且必须和文件名一致
-
不导包创建对象
//创建Scanner对象java.util.Scanner sc = new java.util.Scanner(System.in);//创建 demo11包下的 PingPangPlayer类的对象呢?com.itheima.demo11_coach.PingPangPlayer p1 = new com.itheima.demo11_coach.PingPangPlayer("王励勤", 33);p1.eat();
- 导包
import com.itheima.demo11_coach.PingPangPlayer;import java.util.Scanner;//psvmScanner sc = new Scanner(System.in);PingPangPlayer p1 = new PingPangPlayer("王励勤", 33);p1.eat();
权限修饰符
修饰类, 成员变量, 构造方法, 成员方法, 不同的权限修饰符对应的功能不同
public | protected | 默认 | private | |
---|---|---|---|---|
同一个类中 | √ | √ | √ | √ |
同一个包中的子类或者其他类 | √ | √ | √ | |
不同包中的子类 | √ | √ | ||
不同包中的其他类(无关类) | √ |
记忆
-
访问权限修饰符的权限从大到小分别是:
public > protected > 默认 > private
-
在实际开发中, 如果没有特殊需求, 则成员变量都用private修饰, 其他都用public修饰.
-
大白话总结四个访问权限修饰符的作用:
private: 强调的是给 类自己 使用.
默认: 强调的是给 同包下的类 使用.
protected: 强调的是给 子类 使用.
public: 强调的是给 大家 使用.
Tostring
重写object类的tostring()方法(自动生成),打印该对象的各个属性值
不写的话默认打印地址值
public String toString(){return "cat{" + "name" + name + '\\' '}'}
常用方法
Scanner
产生原因:
1. nextInt()方法的结束标记是: \r\n, 但是该方法只接收整数, 不接收\r\n.
2. nextLine()方法的结束标记是: \r\n, 识别到上边遗留下来的\r\n后, 直接结束了.
解决方案:
1. 采用next()方法解决.
2. 重新调用一次nextLine();
3. 重新new一个Scanner.
4. 实际开发写法: 目前超纲, 先了解.
都用字符串接收, 然后把字符串类型的数字, 转成对应的 int类型的数字即可.
开发中写法
//1. 创建对象.
Scanner sc = new Scanner(System.in);
//2. 提示用户录入
System.out.println("请录入一个整数");
//3. 接收并输出: 整数
String s1 = sc.nextLine();
//核心(超纲): 把字符串数字转成int数字
int num = Integer.parseInt(s1);
System.out.println(num + 3);
//4. 接收并输出: 字符串
System.out.println("请录入一个字符串: ");
String s2 = sc.nextLine();
System.out.println(s2);
Object类
Object类是所有类的父类, 所有的类都直接或者间接继承自Object类.
public class abc (extends object){ }
toString()
- Object类自带的toString()默认打印的是对象的地址值, 无意义, 子类一般都会重写该方法.
- 输出语句直接打印对象, 默认调用了对象的 toString()方法.
equals()
Object类自带的equals()方法, 默认比较的是两个对象的地址值是否相同, 无意义,
子类一般都会重写该方法, 改为比较对象的各个属性值.
- 实际开发中, 我们认为, 如果同一个类型的两个对象, 各个属性值都相同, 那么它们就是同一个对象.
//false, 比较地址值.
System.out.println(s1.equals(s2));
@Override
public boolean equals(Object o) { //s1.equals(s2)
/*
s1: this
s2: o student
*/
//1. 提高效率, 有可能要比较的两个对象是同一个类型的对象.
if (this == o) return true;
//2. 提高健壮性, 有可能要比较的两个对象不是同一个类型的对象.
if (o == null || this.getClass() != o.getClass()) return false;
//3. 向下转型
Student student = (Student) o;
//4. 比较两个对象的年龄是否相同.
if (this.age != student.age) return false;
//5. 比较两个对象的姓名是否相同.
//这里的equals()指的是: String类中的equals()方法
return this.name != null ? this.name.equals(student.name) : student.name == null;
}
String类
String创建对象内存图解
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kWAbOZ1N-1648090035451)(D:\360MoveData\Users\Asus\Desktop\image-20210916094712904.png)]
通过new创建的字符串对象, 每一次new都会申请一个内存堆空间, 虽然内容相同, 但是地址值不同.
char[] chs = {'a', 'b', 'c'};
String s1 = new String(chs);
String s2 = new String(chs);
**//这里的s1和s2的地址值肯定是不同的.**
通过""方式创建的字符串, 只要字符序列相同(顺序和大小写), 无论在程序代码中出现几次**, JVM都只会创建一个String对象, 并在字符串池中维护.**
String s1 = "abc";
String s2 = "abc"; **//这两个对象在内存中其实是同一个对象.**
char[] ==> string
演示 public String(char[] chs); 把接收到的字符数组, 转成其对应的字符串形式.
普通写法
char[] chs = {'h', 'e', '黑','马','程','序','员', 'l', 'l', 'o'};
String s3 = new String(chs);
System.out.println("s3: " + s3);
System.out.println("-------------------");
实际开发写法
String s7 = "abc"; //语法糖.
System.out.println("s7: " + s7);
字符串的比较
String类中的方法
public boolean equals(Object obj); 比较两个字符串是否相等, 比较的是内容, 区分大小写. public boolean equalsIgnoreCase(String s); 比较两个字符串是否相等, 比较的是内容, 不区分大小写.
equals()
System.out.println(s1 == s2); //falseSystem.out.println("-------------------");//5.通过equals()分别判断s1和s2, s1和s3, s3和s4是否相同.System.out.println(s1.equals(s3)); //trueSystem.out.println(s3.equals(s4)); //falseSystem.out.println("-------------------");
equalsIgnoreCase()
//6.通过equalsIgnoreCase()判断字符串abc和ABC是否相同.System.out.println(s3.equalsIgnoreCase("ABC"));
字符串拼接
Java中针对于常量是有优化机制的:
针对于byte类型:
如果是常量相加: 会直接运算, 然后看结果在不在左边的数据类型范围内, 在不报错, 不在就报错.
如果是变量相加: 会提升类型, 然后运算, 提升规则: byte, short, char -> int -> long -> float -> double
针对于String类型:
如果是常量拼接: 会直接拼接, 不会在(堆区)开辟新空间.
如果是变量拼接: 会在堆区开辟新空间.
String s1 = "ab";String s2 = "c";String s3 = "abc";//底层代码,会自动new一个string对象,开辟新的内存空间//System.out.println(s3 == (new StringBuilder()).append(s1).append(s2).toString());//System.out.println(s3 == (new StringBuilder()).append("ab").append(s2).toString());System.out.println(s3 == s1 + s2); //falseSystem.out.println(s3 == "ab" + s2); //falseSystem.out.println(s3 == "ab" + "c"); //true
//案例: 演示遍历字符串.
/*
涉及到的String类中的方法:
public int length(); 获取字符串的长度
public char charAt(int index) 根据索引, 获取其对应的字符.
小细节:
字符串的底层其实就是一个字符数组, 所以字符串中每个元素都是由编号的, 编号是从0开始的.
String类中的方法:
public int length(); 获取字符串的长度
public char charAt(int index) 根据索引, 获取其对应的字符.
for (int i = 0; i < s.length(); i++) { //i就是字符串中, 每个字符的索引 //4. 根据索引, 获取到字符串中的每一个字符. char ch = s.charAt(i); //5. 打印结果. System.out.println(ch);}
if (ch >= 'A' && ch <= 'Z') { //大写字母字符
if(ch >= 'a' && ch <= 'z') { //小写字母字符
if(ch >= '0' && ch <= '9') { //数字字符
public String concat(String str); 拼接字符串, 返回新串.
String s3 = s1 + s2; //s3 = "abc", 会开辟空间(堆)String s4 = s1.concat(s2); //s4 = "abc", 不会开辟堆空间.
字符串反转
for (int i = s.length() - 1; i >= 0; i--) { //方法一:stringbuilder.append() sb.append(s.charAt(i)); } return sb.toString();// //方法三:string.concat()// newStr= newStr.concat(String.valueOf(s.charAt(i))); }// return newStr;// //方法三:string.charAt()// newStr += s.charAt(i) ; }// return newStr; 方法四;object.reverse()// } StringBuilder aaa=new StringBuilder();// aaa.append(s);// StringBuilder newStr1=aaa.reverse();// return newStr1.toString();
StringBuilder
StringBuilder叫: 字符串缓冲区类, 有自带的缓冲区, 可以理解为它是容器,
里边存储的内容是可变的.
StringBuilder中的构造方法:
public StringBuilder(); 空参构造, 创建StringBuilder对象.
public StringBuilder(String str); 带参构造, 创建StringBuilder对象.
可以理解为把 String对象 -> StringBuilder对象.
涉及到的StringBuilder中的方法:
public StringBuilder append(任意类型);
append不会覆盖,append后地址值不变,常量不会开辟新的内存空间
sb.append("黑马程序员").append("夯哥"); for (int i = 0; i < arr.length; i++) sb.append(arr[i]).append(i == arr.length - 1 ? "]" : ", "); return sb.toString();
添加任意类型的数据, 返回StringBuilder本身.
StringBuilder对象反转
public StringBuilder reverse(); 反转StringBuilder对象, 返回StringBuilder本身.
StringBuilder sb3 = sb2.reverse();
String reverseStr = new StringBuilder(str).reverse().toString();System.out.println(reverseStr);
System.out.println(reverse(str));System.out.println("------------------------");
String对象 -> StringBuilder对象
public StringBuilder(String str); 带参构造, 创建StringBuilder对象.
String s2 = "传智播客";StringBuilder sb2 = new StringBuilder(s2); //String对象 -> StringBuilder对象System.out.println("sb2: " + sb2);
StringBuilder对象 -> String对象
StringBuilder类中的toString()方法
public String toString();
返回该对象的字符串形式.
StringBuilder sb = new StringBuilder();sb.append("hello");String s1 = sb.toString();
排序
冒泡排序
//1. 定义数组, 记录要排序的元素.int[] arr = {25, 69, 80, 57, 13};//2. 通过外循环, 控制比较的轮数.//这里的-1是为了啥? 为了提高效率.for (int i = 0; i < arr.length - 1; i++) {//0, 1, 2, 3 //3. 通过内循环, 控制每轮比较的次数. /* 这里的-1是为了啥? 为了防止出现索引越界异常. 这里的-i是为了啥? 为了提高效率. */ for (int j = 0; j < arr.length - 1 - i; j++) { //4, 3, 2, 1 //4. 如果前一个元素比后一个元素大, 就交还它们的位置. //即: arr[j] 和 arr[j + 1] 比较 if (arr[j] > arr[j + 1]) { int temp = arr[j]; arr[j] = arr[j + 1]; arr[j + 1] = temp; } }}//5. for循环执行结束后, 已经排好序了, 我们直接打印数组即可. System.out.println("排序后: " + Arrays.toString(a));
Arrays工具类
工具类介绍:
1. 构造方法私有化.
2. 成员都是静态的, 可以通过 类名. 的形式直接调用.
Arrays类中的成员方法:
public static String toString(int[] arr) 把数组转成其对应的字符串形式, 例如: [1, 3, 5, 6]
public static void sort(int[] arr) 对数组元素进行升序排序.
int[] arr = {25, 69, 80, 57, 13};//补充: 打印排序前的结果Arrays.sort(arr);//3.打印排序后的结果.System.out.println("排序后: " + Arrays.toString(arr));
Integer工具类
public Integer(int value); 把int类型的数据封装成Integer类型的对象,public Integer(String value); 把String类型的数据封装成Integer类型的对象, 注意: 必须是纯数字类型的字符串.
int -> String
//方式一: 直接在数值后边拼接 "", 推荐使用.int a = 10;String s1 = a + "";System.out.println("s1: " + s1);//方式二: String#valueOf()String s2 = String.valueOf(111);System.out.println("s2: " + s2);System.out.println("-----------------------------");
String -> int
//方式1: 转换思路 String -> Integer -> intString s3 = "123";//String -> IntegerInteger i1 = new Integer(s3);//Integer -> intint num1 = i1.intValue();System.out.println("num1: " + num1);//方式2: 通过Integer#parseInt();方法实现, 推荐使用.int num2 = Integer.parseInt(s3);System.out.println("num2: " + num2);
//String -> intint num = Integer.parseInt("123");//String -> doubledouble d = Double.parseDouble("10.3");//String -> booleanboolean flag = Boolean.parseBoolean("false");System.out.println("num: " + num);System.out.println("d: " + d);System.out.println("flag: " + flag);System.out.println("-------------------------------");//2. 演示 字符 -> 字符串之间相互转换, 略.//char -> StringString s1 = 'a' + "";//String -> charchar ch = "abc".charAt(1);//3. 演示 字符数组 -> 字符串之间相互转换,//String -> char[]String str = "黑马程序员";char[] chs = str.toCharArray();//System.out.println(chs); //这里不是地址值,而是数组元素. IO流解释.for (int i = 0; i < chs.length; i++) { char c = chs[i]; System.out.println(c);}// char[] -> StringString str2 = new String(chs);System.out.println("str2: " + str2);
/需求1: 演示自动装箱.//1. 不采用自动装箱int a = 10;Integer i1 = new Integer(a);System.out.println(a);System.out.println(i1);//2. 自动装箱.Integer i2 = a;System.out.println(i2);System.out.println("------------------------");//需求2: 演示自动拆箱//3. 不采用自动拆箱.int b = i1.intValue();System.out.println(b);//4. 采用自动拆箱.int c = i1;System.out.println(c);
Split
//1. 定义变量, 记录要操作的字符串.String s = "91 27 45 38 50";System.out.println(s);//2. 把字符串转成其对应的字符串数组.String[] strArray = s.split(" ");
Date
//1. 演示 public Date(); 采用当前系统默认时间, 生成Date对象.Date d1 = new Date();
//2. 演示 public Date(long time); 采用指定的毫秒值, 生成对应的Date对象.//Java中采用的时间原点是: 1970年1月1日 00:00:00Date d2 = new Date(0L);
获取上述时间对应的毫秒值.System.out.println(d1.getTime());
采用指定的毫秒值, 生成Date对象.//Date d2 = new Date(1590984453616L);Date d2 = new Date();d2.setTime(1590984453616L);System.out.println(d2);
date2String
SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");//SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");//2.2 按照指定的模板进行格式化操作.String result = sdf.format(d1);
string2Date
SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");//2.2 调用SimpleDateFormat#parse()方法, 完成解析操作.Date date = sdf.parse(s);
Calendar
Calendar类中的成员变量: public static final int YEAR 表示年份. public static final int MONTH 表示月份. public static final int DAY_OF_YEAR 表示年中的某一天. public static final int DAY_OF_MONTH 表示月中的某一天. public static final int DAY_OF_WEEK 表示星期中的某一天.Calendar类中的成员方法: public static Calendar getInstance(); 获取Calendar的子类对象. public int get(int field); 根据给定的日历字段, 获取其对应的值. public void set(int year, int month, int day) 设置时间为指定的年, 月, 日. public void add(int field, int count); 设置指定的日历字段, 偏移指定的量.
内部类
内部类分为成员内部类和局部内部类.
成员内部类: 一般多用于框架, 是用来对类的功能进行增强的.
局部内部类: 这个是我们常用的类型,
Person p = new Person() {
@Override
public void eat() {
System.out.println("人要吃饭");
}
@Override
public void sleep() { System.out.println("人要睡觉");
}
@Override
public void study() { System.out.println("人要学习");
}};
p.eat();
p.sleep();
p.study();
匿名内部类
概述:
匿名内部类就是没有名字的 局部内部类.
局部位置: 方法中, 或者方法的形参列表.
格式:
new 类名或者接口名() {
//重写类或者接口中所有的抽象方法.
};
本质:
匿名内部类就是一个继承了类或者实现了接口的匿名的子类对象.
使用场景: 1. 当对对象方法(也叫: 成员方法)仅调用一次的时候. 2. 匿名内部类可以作为方法的实参进行传递.小技巧: 当抽象类或者接口中的抽象方法不超过3个的时候(一般是只有1个), 就可以考虑使用匿名内部类.
Animal.show(new Animal(){ //实际开发经常这样写. @Override public void eat() { System.out.println("匿名内部类创建Animal对象, 重写eat()方法"); }});
IO流
异常
异常简介:
概述:
Java中的异常指的是程序出现不正常的情况.
分类:
Throwable 类, 异常的最顶层类, 所有的异常都是它儿子.
Error: 表示错误, 例如: 服务器宕机, 数据库崩溃, 这些异常一般和我们的代码没关系, 也不需要我们(程序员)处理.
Exception: 表示异常, 这个才是我们常说的异常.
编译期异常: 发生在编译期间的异常, 不处理, 程序编译通不过.
非RuntimeException及其子类, 都叫: 编译期异常.
运行时异常: 发生在运行期间的异常, 不处理, 程序也能通过编译.
指的是RuntimeException及其子类.
JVM默认处理异常的方式:
采用"抛出异常(即: throws)的方式实现, 会将异常的类型, 异常的描述信息, 以及异常出现的位置打印到控制台上.
并终止程序的运行.
try.catch.finally
语句
格式:
try{
//可能出问题的代码
} catch(Exception e) {
//走这里, 说明程序出现异常了, 所以这里写的基本上都是解决方案.
e.printStackTrace(); //该方法会将异常的类型, 描述信息及位置打印到控制台上.
} finally {
//这里的代码正常情况下永远都会执行, 一般是用来释放资源的.
}
特点:
处理完之后, 代码会继续往下执行.
没有return,后面代码都继续跑
**有return,不写finally,就不会运行finally后面代码
声明抛出异常****
• 格式
*throws* 异常的类型; //该内容是写到方法的形参列表之前的.
特点: 处理完后, 程序会终止执行.
file
构造方法(new)
public File(String pathName); 根据传入的路径, 获取对应的File对象.
public File(String parent, String child); 根据传入的父目录和子文件名获取其对应的File对象.
public File(File parent, String child); 根据传入的父目录对象和子文件名获取其对应的File对象.
成员方法 .
public boolean createNewFile(); 创建空文件, 文件不存在就创建返回true, 存在就不创建, 返回false.
public boolean mkdir(); 创建单级文件夹, 其实是: make directory单词的缩写.
public boolean mkdirs(); 创建多级文件夹.
File类的判断功能:
public boolean exists(); //判断指定的文件(夹)是否存在.
public boolean isFile(); //判断给定的路径是否是文件, 默认包含了exists()方法的功能.
public boolean isDirectory(); //判断给定的路径是否是文件夹, 默认包含了exists()方法的功能.
File类的获取功能:
public String getAbsolutePath(); //获取绝对路径.
public String getPath(); //创建对象的时候用什么路径, 就获取什么路径, 一般是用于获取相对路径.
public String getName(); //获取文件(夹)的名字.
public String[] list(); //获取指定的目录下所有的 文件(夹) 的字符串数组形式.
public File[] listFiles(); //获取指定的目录下所有的 文件(夹) 的File对象数组形式.
删除功能
public boolean delete(); 删除文件或者文件夹.
两个小细节:
1. 如果是删除文件夹, 则该文件夹必须为空文件夹.
2. Java中的删除不走回收站.
字节流
输出流
FileOutputStream: 普通的字节输出流, 以字节为单位, 往文件中写数据.
构造方法:
public FileOutputStream(String path); 接收字符串形式的路径
public FileOutputStream(File path); 接收File对象形式的路径.
public FileOutputStream(String path, boolean append); 如果传true, 表示往文件中追加数据, false: 覆盖.
public FileOutputStream(File path, boolean append); 如果传true, 表示往文件中追加数据, false: 覆盖.
成员方法:
public void write(int b); 一次写一个字节
public void write(byte[] bys); 一次写一个字节数组
public void write(byte[] bys, int start, int len); 一次写一个字节数组的一部分
public void close(); 关闭流.
String类中有一个**getBytes()**方法, 可以把字符串转成其对应的字节数组形式.
fos.write("hello".getBytes());//换行符fos.write("\r\n".getBytes()); //window操作系统: \r\n, linux: \n mac: \r
获取字节数组(字节码)
System.out.println(Arrays.toString("静安寺".getBytes()));
GC回收机制
注释 ctrl +/
ctrl +shift +/
/**+enter
输入流
字节输入流 一次读取一个字节数组.
/*
FileInputStream: 普通的字节输入流, 以字节为单位读取数据.
构造方法:
public FileInputStream(String path);
public FileInputStream(File path);
成员方法:
public int read(); 一次读一个字节, 并返回读取到的该字节的ASCII码值, 读不到返回-1
public int read(byte[] bys); 一次读一个字节数组, 并返回读取到的有效字节数,
并将读取到的数据封装到字节数组中, 读不到返回-1
public void close();
(len = fis.read(bys)) != -1 这行代码做了3件事 1. 执行fis.read(bys), 一次读取一个字节数组, 并把读取到的内容存储到bys数组中. 2. 执行len = fis.read(bys) 将读取到的有效字节数赋值给变量len 3. 执行len != -1 如果len不等于-1, 说明读到内容了, 进循环.
java字典read
read(byte[] b) throws IOException
读取 b.length
字节的数据从这个输入流到一个字节数组。这种方法块直到一些输入是可用的。
普通字节流
FileInputStream fis = new FileInputStream("day12/data/1.txt");//2. 创建输出流对象, 关联目的地文件.FileOutputStream fos = new FileOutputStream("day12/data/2.txt");
高效缓冲字节流
BufferedInputStream bis = new BufferedInputStream( new FileInputStream("day12/data/1.avi"));//2. 创建输出流对象, 关联目的地文件.BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("day12/data/5.avi"));
字符流
普通字符流
FileReader fr = new FileReader("day12/data/1.txt"); //只能用默认码表读.//2. 创建输出流对象, 关联目的地文件.FileWriter fw = new FileWriter("day12/data/2.txt"); //只能用默认码表写.
高效字符流
BufferedReader br = new BufferedReader(new FileReader("day12/data/1.txt"));//2. 创建输出流对象, 关联目的地文件.BufferedWriter bw = new BufferedWriter(new FileWriter("day12/data/2.txt"));
按行读写
//3. 定义变量, 记录读取到的内容或者有效字节(符)数.String line = null;//4. 循环读取,只要条件满足就一直读, 并将读取到的内容赋值给变量.while ((line = br.readLine()) != null) { //5. 将读取到的内容写入到目的地文件中. //System.out.println(line); bw.write(line); //小细节, 千万别忘记加 换行 bw.newLine();}//6. 关流, 释放资源.br.close();bw.close();
字符转换流
这里不传码表, 就用默认码表(utf-8)—可省略
InputStreamReader isr = new InputStreamReader(new FileInputStream("day12/data/1.txt"),"utf-8"); //这里不传码表, 就用默认码表(utf-8)//2. 创建输出流对象, 关联目的地文件.OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("day12/data/2.txt")); //因为使用默认码表, 所以码表名省略了.
序列化流
对象中的某个属性的值不想被序列化, 该如何实现?
给该成员变量加一个修饰符: transient.
transient: 被它修饰的成员变量不参与序列化操作.
//1. 创建序列化流, 封装目的地文件.ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("../day12/data/1.txt"));//2. 创建JavaBean对象.Student s = new Student("刘亦菲", 33);//3. 进行序列化操作.oos.writeObject(s);
反序列化流
如果有变量不想被序列化
private transient int age;
反序列化操作. //1. 创建序列化流, 封装数据源文件. ObjectInputStream ois = new ObjectInputStream(new FileInputStream("../day12/data/1.txt")); //2. 进行反序列化操作.Student s = (Student)(ois.readObject());//3. 打印对象. System.out.println(s); //4. 关流. ois.close();
运行时间
long start = System.currentTimeMillis();//1.分别通过四种方式拷贝视频文件, 并观察它们的效率.//2.通过普通的字节流一次读写一个字节的形式实现.//method01(); 138550毫秒//3.通过普通的字节流一次读写一个字节数组的形式实现.//method02(); //70毫秒long end = System.currentTimeMillis();System.out.println("拷贝时间为: " + (end - start));
Commons简化包
FileUtils.copyDirectoryToDirectory(new File("d:/Compile"), new File("d:/dest"));
FileUtils.copyFile(new File("day12/data/1.txt"), new File("day12/data/2.txt"));
按行读写
//3. 定义变量, 记录读取到的内容或者有效字节(符)数.String line = null;//4. 循环读取,只要条件满足就一直读, 并将读取到的内容赋值给变量.while ((line = br.readLine()) != null) { //5. 将读取到的内容写入到目的地文件中. //System.out.println(line); bw.write(line); //小细节, 千万别忘记加 换行 bw.newLine();}//6. 关流, 释放资源.br.close();bw.close();
字符转换流
这里不传码表, 就用默认码表(utf-8)—可省略
InputStreamReader isr = new InputStreamReader(new FileInputStream("day12/data/1.txt"),"utf-8"); //这里不传码表, 就用默认码表(utf-8)//2. 创建输出流对象, 关联目的地文件.OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("day12/data/2.txt")); //因为使用默认码表, 所以码表名省略了.
序列化流
对象中的某个属性的值不想被序列化, 该如何实现?
给该成员变量加一个修饰符: transient.
transient: 被它修饰的成员变量不参与序列化操作.
//1. 创建序列化流, 封装目的地文件.ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("../day12/data/1.txt"));//2. 创建JavaBean对象.Student s = new Student("刘亦菲", 33);//3. 进行序列化操作.oos.writeObject(s);
反序列化流
如果有变量不想被序列化
private transient int age;
反序列化操作. //1. 创建序列化流, 封装数据源文件. ObjectInputStream ois = new ObjectInputStream(new FileInputStream("../day12/data/1.txt")); //2. 进行反序列化操作.Student s = (Student)(ois.readObject());//3. 打印对象. System.out.println(s); //4. 关流. ois.close();
运行时间
long start = System.currentTimeMillis();//1.分别通过四种方式拷贝视频文件, 并观察它们的效率.//2.通过普通的字节流一次读写一个字节的形式实现.//method01(); 138550毫秒//3.通过普通的字节流一次读写一个字节数组的形式实现.//method02(); //70毫秒long end = System.currentTimeMillis();System.out.println("拷贝时间为: " + (end - start));
Commons简化包
FileUtils.copyDirectoryToDirectory(new File("d:/Compile"), new File("d:/dest"));
FileUtils.copyFile(new File("day12/data/1.txt"), new File("day12/data/2.txt"));