Java入门
java入门基础
前言
本篇文章是本人在学习《java面向对象程序设计》一书时的笔记记录,其中所用代码,大部分为书上课程例子,希望能够对大家有所帮助
java特点:简单,面向对象,稳定,与平台无关,多线程,动态
平台无关性:
例如C++等语言,只能对特定的CPU芯片进行编译,芯片更替后需要重新修改编译。平台无关性取决于JVM,虚拟机,类库,以及一些核心文件。
java虚拟机:
java虚拟机负责将字节码翻译成虚拟机所在平台的机器码,并让当前平台运行该机器码。
多线程:
处理器在同一时间只能执行一个线程,处理器通过在不同线程中快速的切换,java有自己的多线程内置机制,没有的例如C++只能通过调用操作系统的多线程机制。
java三大主流平台:
- java SE:开发Java桌面应用程序和服务器应用程序。
- java EE:java企业版,可以构建企业级的服务应用,相对标准版增加了附加类库
- java ME:java微小平台,可嵌入
一,java安装
Java最基础的是安装JDK(java软件开发工具箱),java SE中就提供了标准的JDK。
JDK 主要目录:
bin目录:在其中包含JVM虚拟机,类库以及其他一些核心文件
conf目录:包含用户可配置选项文件,以便更改JDK访问权限,配置安全算法
include目录:JVM调试接口
jmods目录:创建自定义运行时的编译模块。
legal目录:包含模块的许可和版本文件
lib目录:JDK所需的类库和其他文件
注:
JDK包含java运行环境JRE,它由Java虚拟机,类库以及一些核心文件组成,分别存在于bin和lib目录中。
src.zip是java核心API的所有类的java源文件,在lib目录中
API帮助文档
环境变量:
- 设置系统环境变量 :添加变量名java_home(不区分大小写),变量值为安装的JDK的根目录
- 编辑系统环境变量path:不需要添加新的变量名,直接添加值:%JAVA_HOME%\bin。因为前面已经设置过系统环境变量java_home所以此处可以通过%系统环境变量%来代替。通过path可以使其他系统软件找到JDK的位置所在。
java的程序开发步骤:
- 编写源文件:写源代码
- 编译源文件:通过虚拟机编译源文件得到字节码
- 运行程序:使用java SE平台中的Java解释器来执行字节码文件(存在于bin目录中)
**注: **
一个src是源代码文件包,而每一个.java就是一个源文件,在一个.java中只允许存在一个public类而且源文件的名字必须与该类的名字相同
如果源文件中没有public类则名字与哪一个类的名字相同都行
编译:
DOS:磁盘操作命令
- cd 目录名:进入某个子目录
- cd…:推出子目录
- DOS 进行源文件编译命令:javac 源文件名.注意:如果出现javac不是内部或外部命令的提示语,说明系统变量没有设置好
- DOS手动设置环境变量: path JDK根目录\bin
- DOS手动设置环境变量(临时):path JDK根目录\bin;%path%
- 字节码文件:每一个字节码文件只有一个类
- DOS命令:javac 源代码文件 源代码文件(编译多个源代码文件,源代码文件之间用空格分开)
- DOS命令:javac *.java(编译某个目录下所有的源文件代码)
运行:
- 一个java程序必须至少有一个存在主方法的主类,java应用程序总是从主方法开始运行的
- DOS命令:运行java程序 java 源文件名称(不允许出现.java的后缀)
- path环境变量中有一个新值javapath目录下自带解释器,通过添加path环境变量的位置,他所用java解释器也不同。
Java应用程序的基本结构:
- Java基本单位是类
- 解释器运行时虚拟机会将字节码加载到内存中
- 源文件在同一目录时,编译完主函数类,剩下的源文件也会相继编译
注释:
- 单行注释://后写入内容
- 多行注释:使用
/*
开始,*/
结束- idea快速注释快捷键 ctrl+shift+/
**编程风格: **
Allmans风格:大括号每个占一行
Kernighan风格:左大括号再上一行的行尾
二,基本数据类型,数组和枚举类型
标识符就是名字,关键字就是系统提前定义好的名字
- 标识符由字母,下划线,美元符号和数字组成,长度不受限制。
- 第一个字符不能是数字
- 不能是关键词
- 不能时true,false和null(它们也不是标识符)
- Java语言使用Unicode字符集( 65536 65536 65536中字符)
基本数据类型:
逻辑boolean:(常量 true,false)声明可付初值。
整数类型int:(常量:十进制,以O开头的八进制,以Ox开头的十六进制数)生命可付初值
整数类型内存分配4字节,一个字节八位bit
一个数的补码和其原码相加为0
byte型(字节型):分配一个字节
short(短整型):分配两个字节
long(长整型):分配八个字节,常量后需要加后缀L
字符类型char:(常量使用单引号括起来的Unicode中的一个字符)
- 分配两个字节,可以将数字赋值,会自动匹配到字符集对应字符,同时也可以将字符赋值整型变量,会成为在字符集中的对应位置
- 可以使用转义字符“\”将一些键赋值进去
- 浮点类型float:
- 小数常量需要加入后缀f或F
- 2e42f指的是2乘10的42次方指数法
- float变量会储存八位有效数字(从左往右八位)
- 分配四个字节
- 浮点类型double:
- double型常量小数后要加D或d去以省略),保留有效数字16位
- 基本数据类型的转化
存在精度排序 byte short char int long float double
当把级别低的值赋值给级别高的变量时,会隐式自动完成转化
当把级别高的值赋值给级别低的变量时,必须使用显式转换(会造成精度缺失)
当时当该显示转换但是没转换的时候编译器不会检查值的大小,会检查类型
错误示例:
float x=12.4 //这个时候12.4是double类型的常量,这里并没有显示转化,会报错
**输入基本数据: **
需要创建一个Scanner对象,调用的方法:
- nextBoolean();nextByte();nextShort();每个类型都有对应的输入函数
Scanner reader=new Scanner(System.in);
输入堵塞状态:
当键盘缓冲区中没有单词可读就会进入堵塞状态(滞留)
-
回车会刷新键盘缓冲区的内容消除堵塞状态
-
可以通过hasNextInt()来判断下一个单词是否符合目标,是的话,则返回true
while(reader.hasNextDouble())
{
double x=reader.nextDouble();
m=m+1;
sum=sum+x;
}
System.out.print(m+"个数的何为"+sum);
System.out.print(m+"个数的平均值"+sum/m);
}
//他是在键盘缓冲区上对单词进行一个一个的判断,前提是当上一个单词被读取成功
输出基本型数据:
- 输出println输出后换行,而print正常输出
- 可以用加号将变量,表达式和常量数值和字符串并置在一起输出
- 在输出的字符串常量中不允许出现换 分拆成多个字符串常量,这时可以在+号后换行
- 可以通过格式控制符进行输出,输出的函数时printf
数组:
- 数组通过数组名加索引来实现,索引从0开始
- 数组声明,声明元素类型和数组名字,类型可以自定义和使用基本类型
float boy[]; float[] girl[];
- 在java中不允许在声明数组时定义数组元素的个数,会造成语法错误。
- 声明数组后还需要创建数组,创建数组则是分配内存空间
boy=new float[4];
- 数组属于引用型变量,数组变量中存放的时这个数组的首地址
float boy[]=new float[4];
- 数组名.length表示数组一维数组的长度
数组的初始化:
float a[]=new float[5]; //这行代码相当于 float boy[]={1f,2f,3,4f,5f}; //二维数组可以使用 float a[][]={{1},{},···}
- 数组变量可以赋值给数组变量,这个实际上是将数组变量的引用地址改变
注:输出语句直接输出数组变量会直接输出他的引用地址,而输出char行数组,则会直接将其数组内容输出。
如果想要输出char型数组的引用地址时如下所示:
char a[]={'A','你','好'}; System.out.print(""+a);
数组相关java操作:
//通过调用Arrays类中的输出函数可以输出数组的所有元素内容表示成字符串
int a[]={1,2,3,4,5};
System.out.print(Arrays.toString(a));
//复制数组(这个复制函数前提是必须提前先创建好两个数组)
System.arraycopy(a,0,b,0,a.length);
//复制数组(不需要提前处理数组),从0到index
int a[]={1,2,3};
int b[]=Arrays.copyof(a,5);//如果长度超过了元素大小则超出部分按照默认0来赋值。
//复制数组,不需要从零开始
int a[]={1,2,3};
int b[]=Arrays.copyofRange(a,2,5);
//Arrays中的二分查找函数
a是数组
int index=Arrays.binarySearch(a,number); //返回的是索引没有查找到返回的是一个负数
//Arrays中的排序
Arrays.sort(a)//将数组升序排列
java将内存分为栈内存和堆内存:
栈内存:存放定义的数据类型或数组对象的引用变量
堆内存:用来存放由new创建的对象和数组,内存由java虚拟机的自动垃圾回收器来管理
引用变量在程序运行到其作用域之后被释放,而堆内存中的内存不会被释放掉,数组和对象在没有引用变量指向它时才会变成垃圾
java允许使用整型变量来说明数组元素的个数
int size=30;
double number[]=new double[size];+ 当访问的数组索引超过数组元素个数时,编译会通过,但运行时会导致越界异常
枚举类型:
- 首先声明枚举类型
- 定义枚举常量
- 枚举变量只能取枚举类型中的常量
enum Srasonn { spring,springboot,node } Srasonn a; a=Srasonn.spring;
- 枚举类型可以在一个单独的源文件中单独编译,方便使用
三,运算符,表达式和语句
- 算术符号的优先级
- 自增自减 ++x 使用前先自增 x++使用后自增
- 注意在运算式中的精度,表达式的精度按式子中的最高精度进行
- 位运算符
- instanceof运算符(左边是对象,右边是类,判断该对象是否是该类或子类的对象,返回boolean型)
Scanner a=new Scanner(System.in) boolean a=a instanceof Scanner; if(a==true) { System.out.print("a是Scanner的对象"); }
- 空语句:一个分号也是一条语句
- 控制语句:分支语句,开关语句,循环类型
- 分支语句:if else
开关语句:
- 表达式与常量值进行比较,相同运行后面的语句直到遇见break,否者继续执行后面直到遇到break。如果不相同则运行default中的语句,若没有则该switch不进行处理
switch(表达式)
{
case 常量1:
若干语句;
break;
default:
若干语句;
}
注:表达式的值不允出现long型,否则编译时会出现错误
循环语句:
- for循环
- while循环
- do-while循环
- break:退出循环体
- continue:跳过本次循环进行下一次的循环
数组与for循环语句 :
for(int i:a)
{
System.out.print(a[i]);
}
- 声明的循环变量必须和数组的类型相同
- 而且循环变量必须在for循环体内进行说明(是新的循环变量)
枚举类型与for循环体
- 枚举类型的名字.values();可以将枚举中的所有常量赋值给枚举类型的数组
注:便利的是每一个索引位置中元素的值
四,类和对象
面向对象的三个特征:封装,继承,多态
- 封装:数据+操作
- 继承:子类继承父类
- 多态:统一操作不同的传参数据以及对应的操作
书写风格:一般类名的首字母大写,当有多个单词构成是每个单词的首字母都大写
成员变量和局部变量
成员变量:类体中的定义的变量(类体中可以定义lava中的所有变量)
局部变量:在方法体中定义的变量称为局部变量
- 变量的有效范围:成员变量在整个类的所有方法中都有效,有效性与位置无关。局部变量只在声明它的方法内有效,如果是复合语句,则仅在复合语句内有效,再循环语句中也是这样仅在该循环语句中有效
成员变量:
成员变量分为实例变量与类变量,变量用static定义的是类变量,例如
class Dog{ float x; //实例变量 static int a; //类变量(也被称为static变量) }
- 注:如果局部变量与成员变量的名字相同,则在方法能局部变量有效,如果要使用成员变量则需要通过this关键字
方法重载:
- 方法重载是多态性的一种,一个类可以有多个方法具有相同的名字,但这些方法的参数必须不同,亦或者是参数的个数不同(与返回类型不同)
构造方法:
构造方法没有类型,名字必须与类的名字相同
- 对成员变量的操作必须放在方法中
- 方法分为实例方法和类方法,实例方法可以操作实例变量和类变量,而类方法只能操作类变量。
- 一个类中的方法可以相互调用,但是类方法只能够调用类方法
对象:
类是创造对象的模板
类创建对象时会用到构造方法
如果类中没有写构造方法则会默认提出一个构造方法,是无参的(缺省构造方法)
构造方法没有类型,不需要返回值,也不需要void
如果自己定义构造方法则不会给出默认的构造方法
在进行创建对象时,为成员变量分配内存,如果成员变量生命时没有赋初值,则默认值boolean是false,整型为0,浮点型0.0
局部变量声明时如果没有初始化,就没有默认值,因此在使用局部变量之前,要保证该局部变量有值。
java垃圾收集器会将堆中长时间闲置的内容释放掉,不需要使用析构方法(C++).
int a[]=new a[4]; System.gc(a)//调用System中的gc方法会立刻进行垃圾收集,直接释放掉引用的内存
- 向函数传的参数,相当于原变量的一个副本,原变量并不会受到影响
- 传参级别不应该高于被传参数类型级别
- 如果传参的类型是引用性,则两个变量指向共同的位置。
可变参数:
- 参数的类型必须相同,参数的个数不详
- 代表参数可以通过下标的方式进行访问对应的参数,而且可以通过代表参数.length得到参数的个数
public void g(double a,int ··· x);
- 适用于多变型传参传递函数
static关键词:
- 类变量是共享变量,所有该类创建的对象,都共用同一类变量
- 在类加载到内存的时候类中的类变量就分配了内存(在类还没有创建对象的时候类变量就分配了内存)
- 类变量的内存空间在程序结束后才能够进行释放
- 可以直接通过类名访问类变量
- 理解什么时候使用类方法:如果一个方法不需要操作实例成员变量就可以实现某种功能,可以写成类方法
this 关键词
- this关键词表示本对象,可以在构造方法和实例方法中使用
- 类的实例方法可以通过this调用其他的方法
注:实例方法中调用函数可以省略this或类.
注:this不能出现在类方法中,可能此时并没有创建对象
包
- java使用package进行包语言,package必须出现在java源代码中的第一条
- 没有定义包的相同目录下的源文件隶属于同一个包
- 有包名的类,文件路径必须与报名相符,否则虚拟机无法加载
- java语言不允许用户程序使用java作为报名的第一部分
import:
- import必须写在package和源文件之间
- java.lang是java语言的核心类库,系统会自动引进java.lang类
- 引入java包并不会影响程序运行的性能只能会延迟系统编译的时间
- 源文件中的包名和非类库中类的包名相同,让源文件报名路径和该类的包名路左对齐就可以直接使用该类
- 不同的包必须进行路径左对齐在同一目录下才可以互相调用
- 有包名的源文件,无论如何也无法使用无名包的类
- 注:当一个类中引入了两个类的名字是一样的,一个来自其他包,一个是无名包,源文件将使用无名包的类,如果要使用无名包的类,则有包名的类在引用的时候需要将报名也带上
- 同样当是两个包中相同名字的类也不能省略包名
访问权限:
访问权限是指当一个类中创建了一个对象,该对象访问它成员变量和方法是有限制的。
- 注意同一类中的方法可以调用自己的变量和方法,这个是不受访问权限限制的
私有变量和私有方法:
用private修饰的成员变量和方法是私有变量和私有方法
- 在其他类创建的对象不能访问该对象的私有变量和私有方法
- 私有类变量和私有类方法也不行
- 只有在本类中创建的对象才能够访问自己的私有变量和私有方法
- 对象不能够调用私有变量,但可以调用类中的方法来调用成员变量
公有变量和公有方法:
注:使用public修饰的方法和变量可以进行调用
友好变量和友好方法:
不用访问限制关键词修饰的变量和方法是友好变量和友好方法
- 该类与对象所对应的类必须在同一包下。
受保护的成员变量和方法:
- 用protected修饰的成员变量和方法被称为受保护的成员变量和受保护的方法。
- 同样该类与对象所对应的类必须在同一包名下。
**public类与友好类的区别: **
用public修饰的类可以随意创建对象,友好类只能够再同一包下的类创建对象
不能使用protected和pricate修饰类
访问权限从高到低的排列顺序是public,protected和private
基本数据类型的类封装:
- 每一个基本类型都有类封装,可以通过基本数据类型进行构造方法
Double(double num);
- Double对象调用doubleValue()方法可以返回该对象含有的double型数据
- character类实现了对char型数据 的类封装
- 数据类型封装的类中有有一系列针对数据处理的方法可以进行调用
自动装箱与自动拆箱:
- 自动装箱是将基本数据类型或变量直接赋值给基本数据类型封装类
Integer num=new Integer(100); 相当于
int a=100;
Integer num=100;或 Integer num=a;
- 自动拆箱是将基本数据类型封装类中的数据直接赋值给基本数据类型变量。
int x=number+number;相当于
int x=number.intValue()+number.intValue();
反编译器:
- javap 可以将字节码反编译为源码,将列出其中的public方法和public成员变量
javap -private javax.swing.JButton
文件生成器:
- javadoc 可以制作源文件的HTML格式文档
javadoc Example.java //也可以使用参数-d 指定生成文档所在的目录
javadoc注释:
/** 注释内容 */ 可以在注释内容中使用@para 参数名 (对参数给出说明)
@return 文字说明(对方法的返回类型给予说明)
- 给出的注释在将java源文件编译成html文档的时候会展现出来
Jar清单文件:
- Jar清单文件需要和包放在同一父目录下,不在可通过-cp 加绝对路径进行编译
**Var 声明局部变量 **
- 不可以使用var声明成员变量
- 不可以使用var声明方法的参数和方法的返回类型
- 在声明局部变量的时候要向变量赋初值进行判断
- 引用从上下文推断局部变量可使得代码更具可读性,并减少所需的代码量
五,继承与接口
子类与父类:
- 由继承得到的类称为子类,被继承的类称为子类,被继承的类称为父类(超类)。java不支持多重继承,一个子类只有一个父类
- 如果一个类的生命中没有使用extends关键字,这个类被系统默认是Object的子类,Object是java.lang包中的类
class 子类名 extends 父类名{ }
- 子类继承父类可以理解为在在类中创建了一个父类的对象,可以被子类中的实例方法所调用,就和理解的一样,子类和父类如果在同一个包中,则子类继承了父类没有用private修饰的成员变量和方法
- 如果子类和父类不在同一包中则有所不同,子类继承了父类是protected,public修饰的成员变量和方法
- 子类和父类不在同一个包的时候子类无法继承友好型父类
- protected类型的成员变量和方法可以继承
- 创建子类对象的时候会调用父类的构造方法,如果没有指认调用父类的那一构造方法,就会默认调用父类无参的构造方法,虽然子类不能继承父类的私有型变量,但分配内存的时候仍然会分配内存,子类可以通过父类的实例方法调用父类的私有型变量。
- 子类继承父类的类方法
成员变量的隐藏和方法重写:
- 只要子类中声明的成员变量和父类的成员变量同名,子类就隐藏了继承的成员变量,子类创建的对象和实例方法所操作的变量就是子类定义的成员变量
- 但是子类仍然可以通过调用父类的方法操作隐藏的成员变量
方法重写:
- 方法重写就是将子类继承父类的方法进行重写
- 重写的时候方法的类型和父类的类型一致,或者是父类方法的子类型
- 这个方法的名字,参数个数,参数的类型和父类的方法完全相同
- 重写方法不属于新增方法
- 重写后的方法可以操作子类新定义的成员变量也可以操作父类的成员变量
- 如果要使用被隐藏的方法,可以使用关键词super
- 重写父类的方法时,不可以降低方法的访问权限
super:
- 子类不继承父类的构造方法,子类要使用父类的构造方法,必须在子类的构造方法中使用super,必须是在第一条
- 在子类如果没有说明调用父类的构造方法,则默认调用super();默认的无参构造方法
- 所以一般父类再写构造方法的时候都必须带上一个无参的构造方法
- 被隐藏的成员变量和方法必须使用super来调用
final关键词:
- final修饰的类不允许被继承,不允许出现子类
- 被final修饰的方法不允许被子类进行方法重写,不允许子类隐藏继承的方法
- final修饰的局部变量和成员变量就是常量,所以在声明变量的时候就要进行赋值
对象的上转型对象:
- 将子类的创建的引用放在父类对象中,这时称父类是子类对象的上转型对象
- 上转型对象不能操作子类新增的成员变量以及子类新增的方法
- 上转型对象可以访问子类继承或隐藏的成员变量,也可以调用子类继承或重写的方法
- 如果子类重写了父类的方法则上转型对象调用的一定是重写的方法
- 可以将对象的上转型对象强制转换到一个子类对象,这时,该子类对象又具备了子类的所有属性及功能
- 如果子类重写了父类的类方法则子类的上转型对象只能够调用原来的类方法
继承与多态:
- 假若出现父类进行方法但子类都重写了这个方法并产生的行为不同(比如动物不同的叫声)通过上转型对象方法实现
abstract类和方法:
用abstract修饰的类称为抽象类,用它修饰的方法称为抽象方法
不允许使用final和abstract同时修饰同一个方法
abstract修饰的类中可以有abstract方法也可以有非abstract方法,注意,abstract类中也可以没有abstract方法
abstract不能通过new来创建对象
- 如果一个非抽象类是抽象类的子类,则它必须重写父类的抽象方法,给出方法体
- 如果一个abstract类是abstract类的子类,他可以重写也可以继承abstract方法
- 抽象类可以声明对象当不可以创建对象,它可以称为其子类的上转型对象
抽象类存在的意义:抽象类相当于一个标准,与其相关的事物中必须存在这个标准
可以只强调行为准则,但不给出具体的行为即不给出方法体
//具体实例:一个机车类中有所有机车都有的行业规范,加速,刹车,启动。
abstract class 机车(){
abstract void 启动();
abstract void 刹车();
abstract void 加速();
}
//这里举一个手动挡汽车的例子
class 手动挡 extends 机车(){
void 启动(){
System.out.print("踩离合换到一档");
System.out.print("然后慢慢抬起离合");
}
void 加速(){
System.out.print("踩油门");
}
void 刹车(){
System.out.print("踩下离合器,踩刹车板");
System.out.print("然后将挡位换到一档");
}
}
-
注意权限当不能被继承时不能使用abstract
-
在程序设计中,abstract类起到一个规范作用不用关心它的具体实现,是多态实现程序设计的核心技术之一
//例子就像动物发生模仿器
public abstract class animal{
public abstract void cry();
}
//这里再写一个类类中的方法用来承接不同子类创建的对象以实现上转型对象调用不同方法的作用
public class Simaulator{
public void fasheng(animal a){
System.out.print("现在播放");
a.cry();
}
}
//这里写子类
public class mao extends animal{
public void cry(){
System.out.print("喵喵");
}
}
接口:
一个类只能继承一个父类,未改变这种限制,引用接口,一个类可以实现多个接口
接口中包括static常量和方法两部分
接口中不会有变量
接口中所有的抽象方法权限一定是public,接口体中的所有的static常量的访问权限一定是public
接口体中定义的default方法就是可以写方法体,它的访问权限同样也是public
因为都是public访问权限,所以在接口体中可以省略public
不可以使用static和abstract同时修饰一个方法
接口的使用:
- 可以使用接口名访问接口的常量,调用接口中的static方法
//先写一个含有常量和static方法的接口 public interface h{ public static final int a=100; public static void aa(){ System.out.printlin("调用接口static方法"); } } //通过接口名进行调用 h.a; h.aa();
- 类实现接口,一个类通过关键字implements声明自己实现一个或多个接口,如果实现多个接口,用逗号隔开接口名
- 类实现某接口,但类不拥有接口的static方法,拥有接口的常量和default方法
- 接口中的方法访问权限都是public的,重写时不可忽略public
- 如果一个接口不加public修饰,就是友好接口类,友好接口可以被与该接口在同一个包中的类声明实现
- 如果父类实现了某个接口,那么子类就继承了这个接口,子类不必再显示的使用关键字implements声明这个接口。
- 接口也可以被继承,可以通过关键字extends声明一个接口是另一个接口的子接口
**接口回调: **
- 子类实现接口,将创建的对象引用赋给声明的接口变量
public interface ShowMessage{
void 显示商标 (String s);
default void f(){
System.out.println("default 方法");
}
}
//写一个类实现接口
class Tv implements ShowMessage{
public void 显示商标(String s){
System.out.println(s);
}
public void f(){
System.out.println("重写了default方法");
}
}
//进行接口回调
public class Example{
public static void main(String[] args){
ShowMessage sm=null;
sm=new Tv();
sm.显示商标("长城牌电视机");
sm.f();
}
}
接口的核心设计思想:
- 接口的核心设计思想主要是接口回调
- 一般有接口,接口回调承接类(我的理解), 再调用接口
六,内部类,匿名类与Lambda表达式,异常类
内部类:
- 内部类的外嵌类的成员变量在内部类中仍然有效,内部类的方法也可以调用外部类的中的方法
- 在内部类的类体中不可以声明类变量和类方法,在外嵌类的类体中可以用内部类声明对象作为外嵌类的成员
- 内部类仅供它的外嵌类使用,其他类不可以用某个类的内部类声明对象
- 内部类对应的字节码名字格式是”外嵌类$内部类名“
- 内部类可以被修饰为static内部类,static内部类不能操作外嵌类中的实例成员变量,当定义为静态内部类后可以通过调用来创建对象
RedCowFarm.RedCow redCow=new RedCowFarm.RedCow(180,119,6000); //其中,RedCow是RedCowFarm的静态内部类
匿名类:
- 匿名类就是一个子类,由于无名可用,所以不可能用匿名类声明对象,可以直接用匿名类创建一个对象
- 匿名类可以继承父类,也可以重写父类的方法
- 使用匿名类时必然是在某个类中创建对象,所以匿名类一定是内部类
- 匿名类可以访问外嵌类的变量和方法,匿名类的类体中不可以声明static成员变量和方法
- 对于接口,允许接口名和一个类体创建一个匿名对象,此类体被认为是实现了接口的类去掉类声明后的类体,成为匿名类
//假设现在存在一个父类People; //它的匿名类 new People(){ 匿名类的类体 } //对于接口Computable new Computable(){ 实现接口的匿名类的类体 }
Lambda表达式:
- 单接口(只含有一个方法的接口)
- 作用:在使用单接口匿名类的时候使代码变得更加简洁
**异常类: **
try···catch语句:
- 将可能出现的异常操作放在try···catch语句的try部分,当try部分中的某个方法调用发生异常后try部分将立刻结束操作,而转向执行相应的catch部分
- 各个catch参数中的异常类都是Exception的某个子类
- 如果其中两个catch的参数Exception子类之间有父子关系,那么子类catch必须在父类catch的前面
try{ } catch(ExceptionSubClass1 e){} catch(ExceptionSubClass2 e){}
自定义异常类:
- 一个方法在声明时可以使用throws关键字声明要产生的若干个异常,还要给出产生异常的操作,即用相应的异常类创建对象,并用throw抛出该异常对象
- catch的作用就是捕获throw方法抛出的异常对象
public void setAge(int age)throws InterException{ if(age>=160||age<=0){ throw new IntegerException(age); } else{ this.age=age; } }public int getAge(){ System.out.println("年龄"+age+"合理"); return age; }
整理异常类的过程:
1,先定义一个异常类
2,开始写需要操作的类和方法,在编写类的时候需要使用throws先定义异常,再在方法体中定义异常的方法
3,最后在调用操作方法进行判断
public class IntegerException extends Exception{ String message; public IntegerException(int m){ message="年龄"+m+"不合理"; } public String toString(){ return message; } }
finally子语句:
- finally子语句时try···catch语句的可选部分,语法格式如下:
try{} catch{} finally{}
- 在执行try···catch语句后,无论在try部分是否发生异常,finally子语句都会被执行
- 如果在try···catch中执行了return,finally子语句仍然会被执行
- 如果try···catch中出现了System.exit(0)则不会执行子语句
断言语句:
断言语句用于程序不准备通过捕获异常来处理异常的错误
声明断言语句
assert booleanExpression; assert booleanExpression:messageException;
- 其中booleanExpression必须是求值为Boolean型的表达式;messageException可以是求值为字符串的表达式
如果使用 assert booleanExpression,当它的值为false时候,程序从断言语句处停止执行,当它的值为true时,程序从断言语句出继续执行
如果使用assert BooleanExpression:messageException,当它的值为false时,停止执行,并输出messageExpression表达式的值
当使用java解释器的时候默认关闭断言语句,在调试程序的时候可以使用 java - ea mainClass
Scanner scan=new Scanner(System.in); assert number>0:"负数不能求平方根"; //在assert声明的语句中number>0是Boolean型表达式,后面是字符的表达式
七,面向对象设计的基本规则:
UML类图:
- 常被用于描述一个系统的静态结构
- 类的uml图,结构为长方形分为三层,第一层是名字层,正常字体是普通类,斜体字是抽象类
- 第二层是变量层,格式是”变量名字:类型“,在前面需要加入权限符号,public是”+“,protected是”#“,private是”-“,友好型前面不加修饰符
- 第三层是方法层格式是:方法名字(参数列表):类型,权限表示同第二层相同,如果方法是静态方法,则在方法的下面添加下划线
接口的UML图 :
- 接口的名字必须是斜体,还需要用《interface》修饰名字,并且名字和修饰分裂在两行
- 第二层是常量层,权限修饰如上所示
- 第三层是方法层,接口的权限修饰如上所示
泛化关系:
- 一个类是另一个类的子类,这样就是泛化关系,图形是将子类指向父类实线,终点端使用一个空心的三角形表示实现结束
关联关系:
- 如果A类成员变量是用B类来声明的变量,那么A和B是关联关系,称A关联于B,终点端是一个实心三角形
- 关联关系指的是比如A类中存在B类创建的对象,这时A类关联于B类
依赖关系:
- 如果A类中的某个方法的参数用B类(接口)来声明的变量或某个方法返回的数据类型是B类型的,A于B存在依赖关系,A为起始端,用虚线指向B,终点端为实心箭头
实现关系:
- 一个类实现了一个接口,那么这个类和接口就是实现关系,起始端是类终点端是接口实线指向,终点端是空心三角形
注释:
- UML在一个带卷的长方形中显示给出的注释,并使用虚线将这个带卷的长方形和它所注释的实体连接起来
面向抽象原则:
//面向抽象原则,可以理解为核心呈现的操作通过抽象类来进行
//用实际例子来举例
public class 底面积{
double a;
底面积(double a){
this.a=a
}
public double 面积(){
return (3.14*a*a);
}
}
//通过这个类可以将求底面积的操作定义下来,但是所求的底面积仅仅支持圆形底面积,当所操作的类求的体积
中需要的底面积是三角形,该类便支持,如果将该类改为抽象类
public abstract class 底面积{
public abstract double getArea();
}
//如果写成如上的抽象类当面对不同形状的底面积时,我们只需要添加不同的子类继承这个抽象类进行方法重写,再在类中进行运用就能够进行不同要求的计算
开闭原则:
- 对扩展开放对修改关闭,开闭原则易维护,通常也是面向抽象设计原则
多用组合,少用继承原则:
通过继承复用方法的缺点如下:
- 子类从父类继承的方法在编译时刻就确定下来了,所以无法在运行期间改变从父类继承的方法的行为
- 子类和父类是强耦合关系,也就是说,当父类的方法的行为更改时,必然导致子类发生变化。
- 通过继承继续复用也称“白盒”复用,其缺点是父类的内部细节对于子类而言是可见的
组合与复用:
- 如果一个类中有另一个类的对象,,这就是组合
组合的优点:
- 通过组合对象来复用方法也称“黑盒”复用,当前对象对服用对象中的方法是不可见的
- 对象与所包含的对象属于弱耦合关系,如果修改当前对象所包含的类的代码,现在的类不需要改变
- 当前对象可以在运行时刻动态指定所包含的对象
注:Thread.sleep()指的是当前线程挂起,进入指定毫秒数的休眠,方法中的参数是毫秒
高内聚,低耦合:
- 我的理解:高内聚就是相关度极高的模块(方法)写到一块(一个类中),低耦合就是方法使用联系弱
注:框架就是针对某个领域,提供用于开发应用系统的类的集合
八,常用实用类
String类:
- java.lang包中的String类为final类,因此用户不能扩展String类,即String类不可以有子类
- 可以用一个已创建的String对象创建另一个String对象
String tom=new String(s);
- 还可以通过字符数组创建String类的对象
char a[]={'b','o','y'}; String s=new String(a);
- 在创建String对象的时候可以使用构造方法,将部分字符封装
char a[]={'b','o','y'}; String s=new String(a,1,2);
刨析:
String s1,s2; s1="student"; s2="student"; //如上所示字符串常量也是一种对象,java把用户程序中的String常量放在常量池中,可以将字符串常量引用赋值给一个字符串变量 ,每一个常量对象都对应着一个引用
- 可以使用length方法得到字序列的长度
String tom="我们是学生"; int n1; n1=tom.length(); //或者 int n2="你好,hello".length();
- 比较方法
equals(); //将当前对象的字符序列与括号中参数的字符序列进行比较,相同返回true,不相同返回false String a="hhhh"; boolean s=a.equals(hhh); //不能使用关系运算符进行比较"==",因为如果比较的话在关系运算符中字符串比较的是引用,结果肯定为false
- 前后缀判定方法
String tom="260302820829021",jerry="210796709240220" boolean a=tom.startsWith("260") //通过startsWith函数可以判断字符序列前缀是否和参数相同 boolean b=tom.endsWith("021")//通过endsWith函数可以判断字符序列后缀是否和参数相同
- 单个字符序列的比较
s.regionMatches(k,"en",0,2) //regionMatches函数中表示原字符串的起始位置,String型参数表示要匹配的字符序列,0表示要匹配字符序列的起始位置,2表示字符序列的长度
- 按照字典序比较
String str="abcde"; str.compareTo("boy");//compareTo方法将字符串与参数中的字符进行字典序比较,如果大于字典序则返回正值,否则返回负值,相同则返回0;
- contains方法
String a="abcde"; boolean s=ca.contains("ab");//通过contains方法可以判断字符串中是否有参数字符串字段
- indexOf方法
String tom="I am a good cat"; tom.indexOf("a"); tom.indexOf("good",2); //在字符串中检索参数字符串的位置,从指定的地方进行检测,出现参数中的字符则返回第一次检索的索引位置
- substring方法
String tom="ABCDEFG"; String s=tom.substring(2,5); //通过使用substring方法可以返回一个对象,该对象字符串选择参数索引范围内的字符串将对象的引用赋值给新的字符串对象
基本数据类型的相互转化:
int x; String s="123456"; x=Integer.pareseInt(s); //通过pareseInt()可以将字符串中全是数字的字符串,如果字符串中出现了不是数字的字符串,则会抛出NumberFormatException异常 String str=3.14+""; //任何数字和String常量做并运算"+",都将得到一个String对象 String str=String.valueOf(12313.9876) //可以将数值转化为String对象
- 许多类都继承了Object类中的toString方法,可以将对象进行String表示
Date date=new Date(); System.out.print(date.toString());
- 将String型对象字符序列传给char数组
String s="今天天气真好"; char a[]=new char[2]; s.getChars(1,2,a,0);//通过getChars方法将s对象中起始位置为1,终止位置为2的字符序列赋值给起始位置为0的数组a
- toCharArray()方法
char c[]; c="大家好,很高兴认识大家".toCharArray(); //toCharArray方法可以将字符串按照序列赋值给数组**
正则表达式:
一个正则表达式是含有一些具有特殊意义字符的字符序列,这些特殊字符称为正则表达式中的元字符
在正则表达式中可以用中括号括起来若干个字符来表示一个元字符,该元字符代表中括号中的任何一个字符
- 【abc】:代表abc中的任何一个字符
- 【^abc】:代表除了abc中的任何一个字符
- 【a-zA-Z】:代表英文字母中的任何一个
- 【a-d】:代表a~d中的任何一个
注:”.“代表任何一个字符,如果想使用普通意义的点字符,必须先使用【.】或\
有关正则表达式的细节可以查阅java.util.regex包中的Pattern类
常用的正则表达式
- 匹配形如数字的正则表达式
String regex="-?[0-9]\\d*"; //任何形如整数的字符序列都匹配 regex="-?[0-9][0-9]*[.][0-9]+"; //任何形如浮点数的字符序列都与regex相匹配
- 形如email的正则表达式
String regex="\\w+@\\w+\\.[a-z]+(\\.[a-z]+)?" "geng@163.com".matches(regex);//它的值是true,matches是判断匹配正则表达式的函数
- 匹配形如身份证号码的正则表达式
String regex="[1-9][0-9]{16}[a-zA-Z0-9]{1}";
- 匹配年月日的正则表达式
String year="[1-9][0-9]{3}"; String month="((0?[1-9])|(1[012]))"; String day="((0?[1-9][^0-9])|([12][0-9])|(3[01]?))"; String regex=year+"[-./]"+month+"[-./]"+day; //正则表达式中的?表示它前面修饰的字符表达式可能出现也可能不出现
- 匹配替换函数replaceAll()
String s="12hello567"; String result=s.replaceAll("\\d+","你好。"); //函数的作用是将字符序列中与字符串匹配的内容替换成参数中的字符序列
- 字符序列分解函数
//可以使用split函数将字符串中的字符按照参数给定的正则表达式的格式进行分解,并将分解得到的内容赋予到数组中 String d="\\d+"; String a="12年32日的我们"; String b[]=a.split(d);
- 字符序列分析器
StringTokenizer fenxi =new StringTokenizer("we are student"); StringTokenizer fenxi =new StringTokenizer("we,are;student",", ;"); //StringTokenizer对象可以称为字符序列解析器,他会根据特殊字符将字符串分解并将数据存储到fenxi中通过函数进行操作 fenxi.countTokens(); //这个函数可以得到分解单词的数量 fenxi.hasMoreTokens(); //这个函数判断fenxi中是否还有单词有的话返回true,因为fenxi每返回一个单词就会自动删除 fenxi.nextTokens(); //按照顺序返回一个被分解的单词并在fenxi中删除该单词
- Scanner类的对象也可以通过useDelimiter()方法进行调用
String cost="话费清单:市话费76.89元,长途话费167.38元,短信费12.68元"; Scanner scanner=new Scannner(cost); scannner.useDelimiter("[^0123456789.]+"); //这时分解后的单词已经存储在scanner中,可以通过输出nextDouble()等函数将其单词返回。
- StringTokenizer类与Scanner类进行单词分割的效果:StringTokenizer可以将分解后的单词存放在对象实体中,分配内存进行记忆,读写速度快,长度可知,Scanner 只保存分隔符,因此内存使用较小,长度不可知,读写速度慢
- 更多常用类对象如pattern类与Matcher类,
StringBuffer类:
//append方法可以在字符后面追加字符,并返回StringBuffer引用 StringBuffer buffer=new StringBuffer("我喜欢学习"); buffer.append("数学"); //setCharAt()方法 buffer.setCharAt(int n,char ch); //调用这个函数可以将n索引处的字符替换成参数中的ch //insert方法 insert(int index,String str);//此方法可以将字符插入index指定的索引位置 //reverse方法 buffer.reverse(); //将字符串序列反转 //delete方法 delete(int startIndex,int endIndex) //调用该方法从参数起始位置删除到参数终止位置 //replace方法 replace(int startIndex,int endIndex,String str)//该方法是将起始位置到终止位置处替换成参数字符串
日期与时间:
- LocalDate类
AYLocalDate date=LocalDate.now(); //封装本地当前日期有关的数据(年,月,日星期等) LocalDate date=LocalDate.of(1988,12,16);//可以封装指定日期相关数据 date.getDayOfMonth();//返回月中的号码 date.getMonthvalue();//返回月的整数值 date.getMonth();//返回枚举类型的数据例如February date.getYear();//返回年值 date.lengthOfYear();//返回年所含的天数 date.lengthOfMonth();//返回月所含有的天数 date.isLeapYear();//判断是否是闰年
- LocalDateTime类
LocalDateTime date=LocalDateTime.now(); date.getHour()://返回时 date.getMinute()://返回分 date.getSecond()://返回秒 date.getNano();//返回纳秒 LocalDateTime date=LocalDateTime.of(1988,12,16,22,35,55,0);// 封装指定日期的相关数据
- LocalTime类
LocalTime date=LocalTime.now();//该类只封装了时间
- 计算日期的差
//until方法,通过使用until方法可以计算日期之间的时间差值 LocalDateTime dateStart=LocalDateTime.now(); LocalDateTime dateEnd=LocalDateTime.of(2030.11.09); dateStart.until(dateEnd,ChronoUnit.DAYS);//计算两个日期差了多少天 dateStart.until(dateEnd,ChronoUnit.MONTHS);//计算两个日期差了多少月 dateStart.until(dateEnd,ChronoUnit,YEARS);//计算两个日期差了多少年 //如果dateEnd小于dateStart,until方法返回的是负数,在计算日期差时,不足一个单位的零头方法按0计算
//将传参来的date日子从1开始算,并且根据天数创建相应长度的数组,并将每个数组赋予对应天数的变量再返回数组 public class Givetime { public LocalDate[] gettime(LocalDate date){ date=date.withDayOfMonth(1); //可以将日期中的日子更改为1 int days=date.lengthOfMonth(); LocalDate dataArrays[]=new LocalDate[days]; for(int i=0;i<days;i++){ dataArrays[i]=date.plusDays(i); //plusdays方法用来计算日期退后几天 } return dataArrays; } }
Format方法:
- 格式化方法
//通过格式化字符序列"日期:%ty- %tm-%td" LocalDate date=LocalDate.now(); String s=String.format("%ty年%tm月%td日",date,date,date); //format可以通过参数Locale更改时区 String s=String.format(Locale.US,"%ta %<tb %<td %<tY %<tp %<tT",nowTime);
Math类
- Math类中拥有许多数量计算的方法
random() : //产生一个大于等于0,小于1的随机数 round(double a); //返回一个四舍五入后的值
BigInteger类
- 处理大整数的类
add(BigInteger val); //返回当前大整数对象与参数指定的大整数的和 //还有等等关于大整数处理的函数
Random类
- Math提供的类调用的函数random()返回0—1随机数包括0但不包括1,使其产生1~100的随机数
(int)(Math.random()*100)+1; //除此之外还可以通过Randow类进行生成其被称为随机数生成器 Random random=new Random(); random.nextInt();//随机生成一个整数 random.nextInt(100);//随机生成一个0~100的整数 random.nextBoolean();//随机生成一个boolean型数值
- Random有两个构造方法,一个是无参的,一个是有一个种子Random对象作为种子,所谓的随机序列也是在种子的基础上进行一定的算法所得到的随机数序列,既是无序的也是有规律的。如果一直使用相同的种子最后得出来的序列也是相同的,如果使用无参构造方法,则每次构造出来的使用的时间种子都是在当前主板上的时间,即种子是不一样的,随机性更强。
九,输入流和输出流
- 输入流,输出流看作一条通道程序
- 输入流将指向源处写入数据,可以从输入流中读取数据
- 输出流将从源处指向目的地,可以在输出流通道中写入数据,程序的源和目的地可以是键盘,鼠标,内存和显示窗口
File类:
- File对象主要用来获取文件本身的一些信息,例如文件所在的目录,文件的长度和文件的读/写权限不涉及对文件的读写操作。
File(String filename); File(String directoryPath,String filename); File(File f,String filename) //file类的三个构造方法 getName(); //获取文件的名字 canRead(); //判断文件是否可读 canWrite(); //判断文件是否可以被写入 exists();//判断文件是否存在 length(); //获取文件的长度(单位是字节) getAbsolutePath();//获取文件的绝对路径 //还有很多方法可以查询File文档
文件的创建与删除:
File file=new File("C:\myletter","letter.txt"); // 使用File类创建文件对象 createNewFile() //如果上述文件对象没有该文件则会调用这个函数创建文件 delete() //调用删除函数可以删除当前文件 String filename[]=dir.list() //通过list函数可以返回目录下的所有文件
运行可执行文件:
//执行一个本地机上的可执行文件,可以调用Runtime类 Runtime ec; ec=Runtime.getRuntime();//使用类的静态方法创建对象 ec.exec(String command);//通过exec方法打开本机上的一个可执行文件或操作
文件字节流:
- 对文件的操作简单,只是简单的读写操作
//文件字节输入流类的构造方法 FileInputStream(File file);//通过文件对象创建字节流输入对象 FileInputStream(String name);//通过文件路径创建对象 //注:当进行输入流对象的构造方法时输入流的通道就形成了,但是输入流通道可能会造成I/O异常错误,所以创建输入流对象的过程必须写在try···catch中 //输入流对象通过read()方法进行数据的读取,以字节为单位进行数据的读取 int read(); //还可以将文件数据读取到字节数组中 int read(byte b[]); int read(byte b[],int off,int len); //其中off是首字节在数组中的位置,len为读取字节的数量
- 只要不关闭输入流,每次调用read方法都会继续读剩下的内容
- 调用read方法会返回字节个数
字节输出流:
//构造方法 FileOutputStream(String name); FileOutputStream(File file); //输出流是开辟一个目的地的新通道文件,如果该文件不存在则创建文件,如果该文件存在则刷新文件将文件的长度设置为0; FileOutputStream(File file,boolean append) //可以选择是否刷新文件, true则不刷新,false刷新 //通过write方法将字节数组写入文件中 write(byte b[]); write(byte b[],int off,int len);//off是字节数组起始位置
try { File ss = new File("F:/", "hhh.txt"); FileOutputStream a=new FileOutputStream(ss,false); byte d[]="新年快乐".getBytes(); a.write(d); a.close(); } catch (IOException e) { System.out.println("File read error:"+e); } } //getBytes();函数得到字符串的字节类型 //打开流之后在操作结束后需要关闭通过close方法关闭流
- 打开流后需要关闭流,可以将该流缓冲区的内容冲洗掉
文件字符流:
- 文件字符流通过字符数组读取后写入数据
FileReader(String filename); FileWriter(String filename); read();//无参时返回一个整数,有数组参数时返回读取的字符数目 write(int n);//像文件写入一个字符
- 输出流中将数据首先写入到缓冲区中,每当缓冲区溢出的时候,缓冲区的内容会被自动写入到目的地,如果关闭流则缓冲区的内容会立刻被写入到目的地中,可以通过flush()方法来刷新缓冲区(即立即将当前的缓冲区内容写入到目的地中).
缓冲流:
//文件缓冲流的源是字符输入流,,,目的地是字符输出流,所以构造方法的参数是字符输出或输入流对象 BufferedReader(Reader in); BufferedReader(Write out); //创建过程如下 FileReader inOne=new FileReader("Student.txt"); BufferedReader in=new BufferedReader(inOne);//对于输出流也是这样的 String strLine=in.readLine(); //写入方法 write(String s,int off,int len);//off是s的偏移量,len为写入的长度 //缓冲流有一个独特的写入回行符的方法 newLine();
- 将缓冲流与字符流分为上下层流,输入流将数据先读入到缓存中,缓冲流再从缓存中读取数据
- 同样,缓冲流可以通过flush刷新写入缓存区,缓冲流也需要close关闭流
随机流:
//通过RandomAccessFile创建随机流 //构造方法 RandomAccessFile(String name,String mode);//name是文件的名字,mode可取r(只读)或rw(可读写) RandomAccessFile(File file,String mode);
随机流不分输入还是输出,即文件既是源又是目的地
可以调用seek(long a),用来定位流的读/写位置,参数确定读/写位置距离文件开头的字节个数
可以调用getFilePointer()方法获取流的当前读/写位置
RandowAccessFile还有很多的方法可以通过API文档进行查阅
getBytes()函数中参数可以是编码格式例如”ISO-8859-1“
数组流:
- 流的源和目的除了可以是文件外,还可以是计算机内存
ByteArrayInputStream(byte[] buf); ByteArrayInputStream(byte[] buf,int offset,int length);//字节数组流的构造方法,offset是起始位置。 read(); read(byte[] b,int off,int len); //该方法返回读出的字节个数,如果未读出字节,read方法将返回-1 ByteArrayOutputStream(); ByteArrayOutputStream(int size);//第一个构造方法输出流指向一个默认大小为32字节的缓冲区,如果数据溢出,缓冲区容量将自动增加;第二个是指定了缓冲区的大小,同样会自动增加 write(byte[] b,int off, int len);//调用该方法可以将字节数组写入到缓冲区中 toByteArray();//调用该方法可以返回输出流写入缓冲区的所有字节
数据流:
- 使用数组流对象,当读取一个数值时,不必再关心这个数值应当是多少字节
DataInputStream(InputStream in); DataOutputStream(OutputStream out);//构造方法,参数是指定的底层输出流或底层输入流 //该类的方法无关字节可以直接将参数带入指定数据类型 FileOutputStream fos=new FileOutputStream(file); DataOutputStream out=new DataOutputStream(fos); out.writeInt(100); //写入整型数据100 out.writeLong(123456); //写入长整型数据 out.writeChars("How are you doing");//写入字符串类型数组 //同样读取的时候也无关字节 System.out.printf(inData.readInt());//读取int数据 System.out.printf(inData.readFloat());//读取Float型数据
带进度条的输入流:
- 在创建输入流时在读取文件时会弹出一个显示读取速度的进度条,进度条在参数C指定的组建的正前方显示
//构造方法 ProgressMonitorInputStream(Component c,String s,InputStream); //方法体如下,其中缺乏swing中JTextArea类对象text的创建过程 try{ byte b[]=new byte[30]; FileInputStream input=new FileInputStream("hhh.txt"); ProgressMonitorInputStream pro=new ProgressMonitorInputStream(null,"读取txt文件",input); ProgressMonitor p=pro.getProgressMonitor(); int m=-1; while((m=pro.read(b))!=-1){ String s=new String(b,0,m); text.append(s); thread.sleep(200); }
对象流:
- 可以将一个对象写入一个文件,也可以读取一个对象到程序中
//输出流对象 FileOutputStream fileout=new FileOutputStream("tom.txt"); ObiectOutputStream out=new ObjectOutputStream(fileout); //输入流对象 FileInputStream in=new FileInputStream("tom.txt"); ObiectInputStream obin=new ObiectInputStream(in);
- 注意:当使用对象流写入或读入对象时,要保证对象是序列化的。
- 一个类如果实现了Serializable接口,那么这个类创建的对象就是所谓序列化的对象,Serializable接口中没有方法
- 当把一个对象写入对象输出流时,JVM会实现Serializable接口中的方法,将一定格式的文本(对象的序列化信息)写入目的地中,并根据对象的序列化信息创建一个对象
序列化与对象克隆:
- 一个对象调用clone()方法可以获取该对象的克隆对象,但是如果对象中出现引用型成员变量,那么克隆后的成员变量的引用与原对象相同,所以有的时候必须重写clone()方法
- 使用对象流很容易获取一个序列化的对象的克隆,将对象输出流的目的地当作输入流的源读取的对象既是克隆的对象
文件锁:
//RandomAccessFile创建的流操作文件时可以使用文件锁,只要不解除该锁,其他程序无法操作被锁定的文件 //使用文件锁的步骤如下 //1,创建流对象,权限必须是rw RandomAccessFile input=new RandomAccessFile("example.java","rw"); //2,获得到连接到底层文件的FileChannel对象(信道) FileChannel channel=input.getChannel(); //3,对文件加锁,信道通过调用方法tryLock或lock获得一个FileLock(文件锁)对象 FileLock lock=channel.tryLock(); //4.这时文件已经加上了锁,如果要操作文件需要先释放文件锁,文件锁对象调用release(); lock.release();
使用Scanner类解析文件:
- 使用Scanner类和正则表达式来解析文件的特点是以时间换取空间,解析时间较慢但节省内存
File file=new File("hello.java"); Scanner sc=new Scanner(file); //sc将空白作为分隔标记,调用next()方法依次返回file中的单词,如果file的最后一个单词已被next()方法返回,sc调用hasNext()将返回false,否则返回true //也可以通过nextInt(),nextDouble()方法将数字型单词转换为int或double型,如果不是数字型单词,将发生InputMismatchException异常,在处理异常时可以调用next()方法返回非数字化单词
使用正则表达式作为分隔标记解析文件:
//创建Scanner对象,指向要解析的文件,并使用useDelimiter方法指定正则表达式作为分隔标记 File file=new File("hello.java"); Scanner sc=new Scanner(file); sc.useDelimiter(正则表达式);
try{ double price=0; sc=new Scanner(file); sc.useDelimiter("[^0123456789.]+"); //是将所有的非数字字符作为分隔符进行分隔 while(sc.hasNextDouble()){ price=sc.nextDouble(); count++; sun=sun+price; System.out.println(price); } double aver=sun/count; System.out.println("平均价格"+aver); } catch (FileNotFoundException exp){ System.out.println(exp); }
引用与原对象相同,所以有的时候必须重写clone()方法
- 使用对象流很容易获取一个序列化的对象的克隆,将对象输出流的目的地当作输入流的源读取的对象既是克隆的对象
文件锁:
//RandomAccessFile创建的流操作文件时可以使用文件锁,只要不解除该锁,其他程序无法操作被锁定的文件 //使用文件锁的步骤如下 //1,创建流对象,权限必须是rw RandomAccessFile input=new RandomAccessFile("example.java","rw"); //2,获得到连接到底层文件的FileChannel对象(信道) FileChannel channel=input.getChannel(); //3,对文件加锁,信道通过调用方法tryLock或lock获得一个FileLock(文件锁)对象 FileLock lock=channel.tryLock(); //4.这时文件已经加上了锁,如果要操作文件需要先释放文件锁,文件锁对象调用release(); lock.release();
使用Scanner类解析文件:
- 使用Scanner类和正则表达式来解析文件的特点是以时间换取空间,解析时间较慢但节省内存
File file=new File("hello.java"); Scanner sc=new Scanner(file); //sc将空白作为分隔标记,调用next()方法依次返回file中的单词,如果file的最后一个单词已被next()方法返回,sc调用hasNext()将返回false,否则返回true //也可以通过nextInt(),nextDouble()方法将数字型单词转换为int或double型,如果不是数字型单词,将发生InputMismatchException异常,在处理异常时可以调用next()方法返回非数字化单词
使用正则表达式作为分隔标记解析文件:
//创建Scanner对象,指向要解析的文件,并使用useDelimiter方法指定正则表达式作为分隔标记 File file=new File("hello.java"); Scanner sc=new Scanner(file); sc.useDelimiter(正则表达式);
try{ double price=0; sc=new Scanner(file); sc.useDelimiter("[^0123456789.]+"); //是将所有的非数字字符作为分隔符进行分隔 while(sc.hasNextDouble()){ price=sc.nextDouble(); count++; sun=sun+price; System.out.println(price); } double aver=sun/count; System.out.println("平均价格"+aver); } catch (FileNotFoundException exp){ System.out.println(exp); }