什么是Java
Java是一门面向对象的编程语言,不仅吸收了C++语言的各种优点,还摒弃了C++里难以理解的多继承、指针等概念,因此Java语言具有功能强大和简单易用两个特征。Java语言作为静态面向对象编程语言的代表,极好地实现了面向对象理论,允许程序员以优雅的思维方式进行复杂的编程
Java的语言特点
简单性
Java看起来设计得很像C++,但是为了使语言小和容易熟悉,设计者们把C++语言中许多可用的特征去掉了,这些特征是一般程序员很少使用的。例如,Java不支持goto语句,代之以提供break和continue语句以及异常处理。Java还剔除了C++的操作符过载(overload)和多继承特征,并且不使用主文件,免去了预处理程序。因为Java没有结构,数组和串都是对象,所以不需要指针。Java能够自动处理对象的引用和间接引用,实现自动的无用单元收集,使用户不必为存储管理问题烦恼,能更多的时间和精力花在研发上。
面向对象
Java是一个面向对象的语言。对程序员来说,这意味着要注意其中的数据和操纵数据的方法(method),而不是严格地用过程来思考。在一个面向对象的系统中,类(class)是数据和操作数据的方法的集合。数据和方法一起描述对象(object)的状态和行为。每一对象是其状态和行为的封装。类是按一定体系和层次安排的,使得子类可以从超类继承行为。在这个类层次体系中有一个根类,它是具有一般行为的类。Java程序是用类来组织的。
Java还包括一个类的扩展集合,分别组成各种程序包(Package),用户可以在自己的程序中使用。例如,Java提供产生图形用户接口部件的类(java.awt包),这里awt是抽象窗口工具集(abstract windowing toolkit)的缩写,处理输入输出的类(java.io包)和支持网络功能的类(java.net包)。
分布性
Java设计成支持在网络上应用,它是分布式语言。Java既支持各种层次的网络连接,又以Socket类支持可靠的流(stream)网络连接,所以用户可以产生分布式的客户机和服务器。
网络变成软件应用的分布运载工具。Java程序只要编写一次,就可到处运行。
编译和解释性
Java编译程序生成字节码(byte-code),而不是通常的机器码。Java字节码提供对体系结构中性的目标文件格式,代码设计成可有效地传送程序到多个平台。Java程序可以在任何实现了Java解释程序和运行系统(run-time system)的系统上运行。
在一个解释性的环境中,程序开发的标准“链接”阶段大大消失了。如果说Java还有一个链接阶段,它只是把新类装进环境的过程,它是增量式的、轻量级的过程。因此,Java支持快速原型和容易试验,它将导致快速程序开发。这是一个与传统的、耗时的“编译、链接和测试”形成鲜明对比的精巧的开发过程。
稳健性
Java原来是用作编写消费类家用电子产品软件的语言,所以它是被设计成写高可靠和稳健软件的。Java消除了某些编程错误,使得用它写可靠软件相当容易。
Java是一个强类型语言,它允许扩展编译时检查潜在类型不匹配问题的功能。Java要求显式的方法声明,它不支持C风格的隐式声明。这些严格的要求保证编译程序能捕捉调用错误,这就导致更可靠的程序。
可靠性方面最重要的增强之一是Java的存储模型。Java不支持指针,它消除重写存储和讹误数据的可能性。类似地,Java自动的“无用单元收集”预防存储漏泄和其它有关动态存储分配和解除分配的有害错误。Java解释程序也执行许多运行时的检查,诸如验证所有数组和串访问是否在界限之内。
异常处理是Java中使得程序更稳健的另一个特征。异常是某种类似于错误的异常条件出现的信号。使用try/catch/finally语句,程序员可以找到出错的处理代码,这就简化了出错处理和恢复的任务。
安全性
Java的存储分配模型是它防御恶意代码的主要方法之一。Java没有指针,所以程序员不能得到隐蔽起来的内幕和伪造指针去指向存储器。更重要的是,Java编译程序不处理存储安排决策,所以程序员不能通过查看声明去猜测类的实际存储安排。编译的Java代码中的存储引用在运行时由Java解释程序决定实际存储地址。
Java运行系统使用字节码验证过程来保证装载到网络上的代码不违背任何Java语言限制。这个安全机制部分包括类如何从网上装载。例如,装载的类是放在分开的名字空间而不是局部类,预防恶意的小应用程序用它自己的版本来代替标准Java类。
可移植性
Java使得语言声明不依赖于实现的方面。例如,Java显式说明每个基本数据类型的大小和它的运算行为(这些数据类型由Java语法描述)。
Java环境本身对新的硬件平台和操作系统是可移植的。Java编译程序也用Java编写,而Java运行系统用ANSIC语言编写。
高性能
Java是一种先编译后解释的语言,所以它不如全编译性语言快。但是有些情况下性能是很要紧的,为了支持这些情况,Java设计者制作了“及时”编译程序,它能在运行时把Java字节码翻译成特定CPU(中央处理器)的机器代码,也就是实现全编译了。
Java字节码格式设计时考虑到这些“及时”编译程序的需要,所以生成机器代码的过程相当简单,它能产生相当好的代码。
多线程性
Java是多线程语言,它提供支持多线程的执行(也称为轻便过程),能处理不同任务,使具有线索的程序设计很容易。Java的lang包提供一个Thread类,它支持开始线索、运行线索、停止线索和检查线索状态的方法。
Java的线索支持也包括一组同步原语。这些原语是基于监督程序和条件变量风范,由C.A.R.Haore开发的广泛使用的同步化方案。用关键词synchronized,程序员可以说明某些方法在一个类中不能并发地运行。这些方法在监督程序控制之下,确保变量维持在一个一致的状态。
动态性
Java语言设计成适应于变化的环境,它是一个动态的语言。例如,Java中的类是根据需要载入的,甚至有些是通过网络获取的。
Java的工作原理
说到Java自然离不开JDK、JVM、JRE,三者有什么关系。
JDK
(Java Development Kit)Java开发工具包,包含Java语言、Java虚拟机、Java类库,是支持Java程序开发的最小环境。
JVM
(Java Virtual Machine)Java虚拟机,运行于各种操作系统Linux,Windows,Solaris等之上,执行编译好的Java字节码class文件。
JRE
(Java Runtime Environment)Java运行时环境,包含JavaSE中核心类库API和Java虚拟机,简单理解为JVM+核心类库API。
Java的运行流程
Java源文件->编译(javac命令)得到.class:字节码文件(二进制文件)->运行(java命令)
IDE
IDE 是 Integrated Development Environment 的缩写,中文称为集成开发环境,用来表示辅助程序员开发的应用软件,是它们的一个总称。
常见的IDE集成开发环境
- Eclipse
- IntelliJ IDEA
- NetBeans
- Visual Studio Code (VSCode)
Java是如何实现跨平台的,原理是什么?
Java语言目前很流行和Java很多优点分不开而Java的最大优点是就是跨平台。Java跨平台可以使用8个字概括:一次编译到处运行。
什么是Java实现跨平台
Java实现跨平台,是指java语言编写的程序,经过一次编译后,可以在多个系统平台上运行。
原理
java程序的跨平台主要是指字节码文件可以在任何具有JVM的计算机和电子设备上运 行,Java虚拟机中的java解释器负责将字节码文件解释成特定的机器码进行运行。
Java语言本质上是不能跨平台的,真正实现跨平台的是JVM,也就是Java虚拟机。写好的Java源文件通过Javac命令编译生成class文件(中间文件),然后JVM对class文件进行执行生成机器语言然后机器语言在平台中操作,Java在不同的平台下都有对应的不同版本的JVM,JVM可以识别字节码文件从而运行。
变量
Java变量的定义在程序运行期间,随时可能产生一些临时数据,应用程序会将这些数据保存在一些内存单元中,每个内存单元都用一个标识符来标识。这些内存单元被称为变量,定义的标识符就是变量名,内存单元中存储的数据就是变量的值。
变量类型
- 类变量:独立于方法之外的变量,用 static 修饰。
- 实例变量:独立于方法之外的变量,不过没有 static 修饰。
- 局部变量:类的方法中的变量。
示列:
public class Variable{
static int allClicks=0; // 类变量
String str="hello world"; // 实例变量
public void method(){
int i =0; // 局部变量
}
}
数据类型
类型名称 | 关键字 | 占用内存 | 取值范围 |
---|---|---|---|
字节型 | byte | 1 字节 | -128~127 |
短整型 | short | 2 字节 | -32768~32767 |
整型 | int | 4 字节 | -2147483648~2147483647 |
长整型 | long | 8 字节 | -9223372036854775808L~9223372036854775807L |
单精度浮点型 | float | 4 字节 | +/-3.4E+38F(6~7 个有效位) |
双精度浮点型 | double | 8 字节 | +/-1.8E+308 (15 个有效位) |
字符型 | char | 2 字节 | ISO 单一字符集 |
布尔型 | boolean | 1 字节 | true 或 false |
变量的定义
变量声明
数据类型 变量名;
声明的同时并赋值
数据类型 变量名 = 变量值;
同时定义 多个类型相同的变量
数据类型 变量名1 = 值1,变量名2 = 值2,变量名3 ....;
变量命名规则
序号 | 条 件 | 合法变量名 | 非法变量名 |
---|---|---|---|
1 | 变量必须以数字、下划线"_"或"$"返回开头 | _myCar | * myvariablel //不能以*开头 |
2 | 变量可以包括数字,但不能以数字开头 | scorel | 9var-iable //不能以数字开头和不能包括连字符 |
3 | 除了"_"或"$"返回以外,变量名不能包含任何特殊字符 | $muCar | varible% //不能包含% |
4 | 不能使用Java语言的关键字,如int、class、public等 | graph1_1 | a+ b //不能包括+和空格 |
常量
在Java中,利用关键字 final 指示常量。
关键字 final 表示这个变量只能被赋值一次。一旦被赋值之后,就不能够再更改了。习惯上,常量名用全部大写。在Java 中,经常希望某个常量可以在一个类的多个方法中使用,通常将这些常量称为类常量(class constant)。
示列:
package constant;
public class Demo {
final static double PI = 3.1515926;
public static void main(String[] args) {
double r = 3;
System.out.println("圆的面积接近于:" + PI * r * r);
}
}
定义语法
final static 类型名 常量名 = 常量值;
运算符
运算符 | 说明 | 举例 |
---|---|---|
+ | 加分运算符,求操作数的和 | 5+3 等于8 |
- | 减法运算符,求操作数的差 | 5-3 等于2 |
* | 乘法运算符,求操作数的乘 | 5*3 等于15 |
/ | 除法运算符,求操作数的商 | 5/3 等于1 |
% | 取余运算符,求操作数相除的余数 | 5%3 等于2 |
if 语句
条件语句 -if...else
一个 if 语句包含一个布尔表达式和一条或多条语句
语法如下:
if(布尔表达式)
{
//如果布尔表达式为true将执行的语句
}
示列:
public class Test {
public static void main(String args[]){
int x = 10;
if( x < 20 ){
System.out.print("这是 if 语句");
}
}
}
输出结果:
这是 if 语句
if...else语句
if 语句后面可以跟 else 语句,当 if 语句的布尔表达式值为 false 时,else 语句块会被执行。
语法如下:
if(布尔表达式){
//如果布尔表达式的值为true
}else{
//如果布尔表达式的值为false
}
示列:
public class Test {
public static void main(String args[]){
int x = 30;
if( x < 20 ){
System.out.print("这是 if 语句");
}else{
System.out.print("这是 else 语句");
}
}
}
输出结果:
这是 else 语句
if...else if...else 语句
if 语句后面可以跟 else if…else 语句,这种语句可以检测到多种可能的情况。
使用 if,else if,else 语句的时候,需要注意下面几点:
- if 语句至多有 1 个 else 语句,else 语句在所有的 else if 语句之后。
- if 语句可以有若干个 else if 语句,它们必须在 else 语句之前。
- 一旦其中一个 else if 语句检测为 true,其他的 else if 以及 else 语句都将跳过执行。
语法如下:
if(布尔表达式 1){
//如果布尔表达式 1的值为true执行代码
}else if(布尔表达式 2){
//如果布尔表达式 2的值为true执行代码
}else if(布尔表达式 3){
//如果布尔表达式 3的值为true执行代码
}else {
//如果以上布尔表达式都不为true执行代码
}
示列:
public class Test {
public static void main(String args[]){
int x = 30;
if( x == 10 ){
System.out.print("Value of X is 10");
}else if( x == 20 ){
System.out.print("Value of X is 20");
}else if( x == 30 ){
System.out.print("Value of X is 30");
}else{
System.out.print("这是 else 语句");
}
}
}
输出结果:
Value of X is 30
嵌套的 if…else 语句
使用嵌套的 if…else 语句是合法的。也就是说你可以在另一个 if 或者 else if 语句中使用 if 或者 else if 语句。
语法如下:
if(布尔表达式 1){
////如果布尔表达式 1的值为true执行代码
if(布尔表达式 2){
////如果布尔表达式 2的值为true执行代码
}
}
示列:
public class Test {
public static void main(String args[]){
int x = 30;
int y = 10;
if( x == 30 ){
if( y == 10 ){
System.out.print("X = 30 and Y = 10");
}
}
}
}
输出结果:
X = 30 and Y = 10
switch case 语句
switch case 语句判断一个变量与一系列值中某个值是否相等,每个值称为一个分支。
语法格式:
switch(expression){
case value :
//语句
break; //可选
case value :
//语句
break; //可选
//你可以有任意数量的case语句
default : //可选
//语句
}
规则
- switch 语句可以拥有多个 case 语句。每个 case 后面跟一个要比较的值和冒号。
- case 语句中的值的数据类型必须与变量的数据类型相同,而且只能是常量或者字面常量。
- 当变量的值与 case 语句的值相等时,那么 case 语句之后的语句开始执行,直到 break 语句出现才会跳出 switch 语
句。
- 当遇到 break 语句时,switch 语句终止。程序跳转到 switch 语句后面的语句执行。case 语句不必须要包含 break 语句。如果没有 break 语句出现,程序会继续执行下一条 case 语句,直到出现 break 语句。
- switch 语句可以包含一个 default 分支,该分支一般是 switch 语句的最后一个分支(可以在任何位置,但建议在最后一个)。default 在没有 case 语句的值和变量值相等的时候执行。default 分支不需要 break 语句。
switch case 执行时,一定会先进行匹配,匹配成功返回当前 case 的值,再根据是否有 break,判断是否继续输出,或是跳出判断。
示列:
public class Test {
public static void main(String args[]){
//char grade = args[0].charAt(0);
char grade = 'C';
switch(grade)
{
case 'A' :
System.out.println("优秀");
break;
case 'B' :
case 'C' :
System.out.println("良好");
break;
case 'D' :
System.out.println("及格");
break;
case 'F' :
System.out.println("你需要再努力努力");
break;
default :
System.out.println("未知等级");
}
System.out.println("你的等级是 " + grade);
}
}
运行结果:
良好
你的等级是 C
如果 case 语句块中没有 break 语句时,JVM 并不会顺序输出每一个 case 对应的返回值,而是继续匹配,匹配不成功则返回默认 case。
public class Test {
public static void main(String args[]){
int i = 5;
switch(i){
case 0:
System.out.println("0");
case 1:
System.out.println("1");
case 2:
System.out.println("2");
default:
System.out.println("default");
}
}
}
运行结果:
default
如果 case 语句块中没有 break 语句时,匹配成功后,从当前 case 开始,后续所有 case 的值都会输出。
public class Test {
public static void main(String args[]){
int i = 1;
switch(i){
case 0:
System.out.println("0");
case 1:
System.out.println("1");
case 2:
System.out.println("2");
default:
System.out.println("default");
}
}
}
运行结果:
1
2
default
如果当前匹配成功的 case 语句块没有 break 语句,则从当前 case 开始,后续所有 case 的值都会输出,如果后续的 case 语句块有 break 语句则会跳出判断。
public class Test {
public static void main(String args[]){
int i = 1;
switch(i){
case 0:
System.out.println("0");
case 1:
System.out.println("1");
case 2:
System.out.println("2");
case 3:
System.out.println("3"); break;
default:
System.out.println("default");
}
}
}
运行结果:
1
2
3
while 语句
语法如下:
while( 布尔表达式 ) {
//循环内容
}
只要布尔表达式为 true,循环就会一直执行下去。
示列:
public class Test {
public static void main(String[] args) {
int x = 10;
while( x < 20 ) {
System.out.print("value of x : " + x );
x++;
System.out.print("\n");
}
}
}
运行结果:
value of x : 10
value of x : 11
value of x : 12
value of x : 13
value of x : 14
value of x : 15
value of x : 16
value of x : 17
value of x : 18
value of x : 19
do…while 语句
对于 while 语句而言,如果不满足条件,则不能进入循环。但有时候我们需要即使不满足条件,也至少执行一次。
do…while 循环和 while 循环相似,不同的是,do…while 循环至少会执行一次。
语句如下:
do {
//代码语句
}while(布尔表达式);
注意:布尔表达式在循环体的后面,所以语句块在检测布尔表达式之前已经执行了。 如果布尔表达式的值为 true,则语句块一直执行,直到布尔表达式的值为 false。
示列:
public class Test {
public static void main(String[] args){
int x = 10;
do{
System.out.print("value of x : " + x );
x++;
System.out.print("\n");
}while( x < 20 );
}
}
运行结果:
value of x : 10
value of x : 11
value of x : 12
value of x : 13
value of x : 14
value of x : 15
value of x : 16
value of x : 17
value of x : 18
value of x : 19
for 语句
for 语句比较简单,用于循环数据。
for循环执行的次数是在执行前就确定的。
语法格式如下:
for(初始化; 布尔表达式; 更新) {
//代码语句
}
示列:
public class Main {
public static void main(String[] args) {
int[] intary = { 1,2,3,4};
forDisplay(intary);
foreachDisplay(intary);
}
public static void forDisplay(int[] a){
System.out.println(" for 循环数组");
for (int i = 0; i < a.length; i++) {
System.out.print(a[i] + " ");
}
System.out.println();
}
}
运行结果:
for 循环数组
1 2 3 4
break 关键字
break 主要用在循环语句或者 switch 语句中,用来跳出整个语句块。
break 跳出最里层的循环,并且继续执行该循环下面的语句。
示列:
public class Test {
public static void main(String[] args) {
int [] numbers = {10, 20, 30, 40, 50};
for(int x : numbers ) {
// x 等于 30 时跳出循环
if( x == 30 ) {
break;
}
System.out.print( x );
System.out.print("\n");
}
}
}
运行结果:
10
20
continue 关键字
continue 适用于任何循环控制结构中。作用是让程序立刻跳转到下一次循环的迭代。
在 for 循环中,continue 语句使程序立即跳转到更新语句。
在 while 或者 do…while 循环中,程序立即跳转到布尔表达式的判断语句。
示列:
public class Test {
public static void main(String[] args) {
int [] numbers = {10, 20, 30, 40, 50};
for(int x : numbers ) {
if( x == 30 ) {
continue;
}
System.out.print( x );
System.out.print("\n");
}
}
}
运行结果:
10
20
40
50
数组
数组对于每一门编程语言来说都是重要的数据结构之一,当然不同语言对数组的实现及处理也不尽相同。
Java 语言中提供的数组是用来存储固定大小的同类型元素。
你可以声明一个数组变量,如 numbers[100] 来代替直接声明 100 个独立变量 number0,number1,....,number99。
创建数组
Java语言使用new操作符来创建数组,语法如下:
arrayRefVar = new dataType[arraySize];
上面的语法语句做了两件事:
- 一、使用 dataType[arraySize] 创建了一个数组。
- 二、把新创建的数组的引用赋值给变量 arrayRefVar。
数组变量的声明,和创建数组可以用一条语句完成,如下所示:
dataType[] arrayRefVar = new dataType[arraySize];
另外,你还可以使用如下的方式创建数组。
dataType[] arrayRefVar = {value0, value1, ..., valuek};
数组的元素是通过索引访问的。数组索引从 0 开始,所以索引值从 0 到 arrayRefVar.length-1。
示列:
public class TestArray {
public static void main(String[] args) {
// 数组大小
int size = 10;
// 定义数组
double[] myList = new double[size];
myList[0] = 5.6;
myList[1] = 4.5;
myList[2] = 3.3;
myList[3] = 13.2;
myList[4] = 4.0;
myList[5] = 34.33;
myList[6] = 34.0;
myList[7] = 45.45;
myList[8] = 99.993;
myList[9] = 11123;
// 计算所有元素的总和
double total = 0;
for (int i = 0; i < size; i++) {
total += myList[i];
}
System.out.println("总和为: " + total);
}
}
运行结果:
总和为: 11367.373
下面的图片描绘了数组 myList。这里 myList 数组里有 10 个 double 元素,它的下标从 0 到 9。
处理数组
数组的元素类型和数组的大小都是确定的,所以当处理数组元素时候,我们通常使用基本循环或者 For-Each 循环。
示例:
该实例完整地展示了如何创建、初始化和操纵数组:
public class TestArray {
public static void main(String[] args) {
double[] myList = {1.9, 2.9, 3.4, 3.5};
// 打印所有数组元素
for (int i = 0; i < myList.length; i++) {
System.out.println(myList[i] + " ");
}
// 计算所有元素的总和
double total = 0;
for (int i = 0; i < myList.length; i++) {
total += myList[i];
}
System.out.println("Total is " + total);
// 查找最大元素
double max = myList[0];
for (int i = 1; i < myList.length; i++) {
if (myList[i] > max) max = myList[i];
}
System.out.println("Max is " + max);
}
}
运行结果:
1.9
2.9
3.4
3.5
Total is 11.7
Max is 3.5
类和对象
类是对象的抽象,对象是类的实例
- 对象:对象是类的一个实例(对象不是找个女朋友),有状态和行为。例如,一条狗是一个对象,它的状态有:颜色、名字、品种;行为有:摇尾巴、叫、吃等。
- 类:类是一个模板,它描述一类对象的行为和状态。
面向对象的三大特征(OOP)
面向对象编程(OOP,Object Oriented Programming),所谓的面向对象是一种编程思想,通过这种思想可以把生活中的复杂事情变得简单化,从原来的执行者变成了指挥者,面向对象是基于面向过程而言的.
- 封装性,把相关的数据封装成一个“类”组件
- 继承性,是子类自动共享父类属性和方法,这是类之间的一种关系
- 多态,增强软件的灵活性和重用性
封装
封装是指隐藏对象的属性和实现细节,仅仅对外提供公共的访问方式
封装的好处
- 提高安全性
- 提高重用性
private关键字
是一个权限修饰符,用于修饰成员变量和成员函数,被私有化的成员只能在本类中访问。
想要修改只能,对外提供公共的,get和set方法
语法:
private 数据类型 变量名;
继承
继承是java面向对象编程技术的一块基石,因为它允许创建分等级层次的类。
继承就是子类继承父类的特征和行为,使得子类对象(实例)具有父类的实例域和方法,或子类从父类继承方法,使得子类具有父类相同的行为。
兔子和羊属于食草动物类,狮子和豹属于食肉动物类。
食草动物和食肉动物又是属于动物类。
所以继承需要符合的关系是:is-a,父类更通用,子类更具体。
虽然食草动物和食肉动物都是属于动物,但是两者的属性和行为上有差别,所以子类会具有父类的一般特性也会具有自身的特性。
类的继承格式
在 Java 中通过 extends 关键字可以申明一个类是从另外一个类继承而来的,一般形式如下:
class 父类 {
}
class 子类 extends 父类 {
}
为什么需要继承
接下来我们通过实例来说明这个需求。
开发动物类,其中动物分别为企鹅以及老鼠,要求如下:
- 企鹅:属性(姓名,id),方法(吃,睡,自我介绍)
- 老鼠:属性(姓名,id),方法(吃,睡,自我介绍)
企鹅类:
public class Penguin {
private String name;
private int id;
public Penguin(String myName, int myid) {
name = myName;
id = myid;
}
public void eat(){
System.out.println(name+"正在吃");
}
public void sleep(){
System.out.println(name+"正在睡");
}
public void introduction() {
System.out.println("大家好!我是" + id + "号" + name + ".");
}
}
老鼠类:
public class Mouse {
private String name;
private int id;
public Mouse(String myName, int myid) {
name = myName;
id = myid;
}
public void eat(){
System.out.println(name+"正在吃");
}
public void sleep(){
System.out.println(name+"正在睡");
}
public void introduction() {
System.out.println("大家好!我是" + id + "号" + name + ".");
}
}
从这两段代码可以看出来,代码存在重复了,导致后果就是代码量大且臃肿,而且维护性不高(维护性主要是后期需要修改的时候,就需要修改很多的代码,容易出错),所以要从根本上解决这两段代码的问题,就需要继承,将两段代码中相同的部分提取出来组成 一个父类:
公共父类:
public class Animal {
private String name;
private int id;
public Animal(String myName, int myid) {
name = myName;
id = myid;
}
public void eat(){
System.out.println(name+"正在吃");
}
public void sleep(){
System.out.println(name+"正在睡");
}
public void introduction() {
System.out.println("大家好!我是" + id + "号" + name + ".");
}
}
这个Animal类就可以作为一个父类,然后企鹅类和老鼠类继承这个类之后,就具有父类当中的属性和方法,子类就不会存在重复的代码,维护性也提高,代码也更加简洁,提高代码的复用性(复用性主要是可以多次使用,不用再多次写同样的代码) 继承之后的代码:
企鹅类:
public class Penguin extends Animal {
public Penguin(String myName, int myid) {
super(myName, myid);
}
}
老鼠类:
public class Mouse extends Animal {
public Mouse(String myName, int myid) {
super(myName, myid);
}
}
继承类型
需要注意的是 Java 不支持多继承,但支持多重继承。
继承的特性
- 子类拥有父类非 private 的属性、方法。
- 子类可以拥有自己的属性和方法,即子类可以对父类进行扩展。
- 子类可以用自己的方式实现父类的方法。
- Java 的继承是单继承,但是可以多重继承,单继承就是一个子类只能继承一个父类,多重继承就是,例如 B 类继承 A 类,C 类继承 B 类,所以按照关系就是 B 类是 C 类的父类,A 类是 B 类的父类,这是 Java 继承区别于 C++ 继承的一个特性。
- 提高了类之间的耦合性(继承的缺点,耦合度高就会造成代码之间的联系越紧密,代码独立性越差)。
继承关键字
继承可以使用 extends 和 implements 这两个关键字来实现继承,而且所有的类都是继承于 java.lang.Object,当一个类没有继承的两个关键字,则默认继承 Object(这个类在 java.lang 包中,所以不需要 import)祖先类。
extends关键字
在 Java 中,类的继承是单一继承,也就是说,一个子类只能拥有一个父类,所以 extends 只能继承一个类。
语法如下:
public class Animal {
private String name;
private int id;
public Animal(String myName, int myid) {
//初始化属性值
}
public void eat() { //吃东西方法的具体实现 }
public void sleep() { //睡觉方法的具体实现 }
}
public class Penguin extends Animal{
}
implements关键字
使用 implements 关键字可以变相的使java具有多继承的特性,使用范围为类继承接口的情况,可以同时继承多个接口(接口跟接口之间采用逗号分隔)。
public interface A {
public void eat();
public void sleep();
}
public interface B {
public void show();
}
public class C implements A,B {
}
super 与 this 关键字
super关键字:我们可以通过super关键字来实现对父类成员的访问,用来引用当前对象的父类。
this关键字:指向自己的引用。
示列:
class Animal {
void eat() {
System.out.println("animal : eat");
}
}
class Dog extends Animal {
void eat() {
System.out.println("dog : eat");
}
void eatTest() {
this.eat(); // this 调用自己的方法
super.eat(); // super 调用父类方法
}
}
public class Test {
public static void main(String[] args) {
Animal a = new Animal();
a.eat();
Dog d = new Dog();
d.eatTest();
}
}
运行结果:
animal : eat
dog : eat
animal : eat
final 关键字
final 可以用来修饰变量(包括类属性、对象属性、局部变量和形参)、方法(包括类方法和对象方法)和类。
final 含义为 "最终的"。
使用 final 关键字声明类,就是把类定义定义为最终类,不能被继承,或者用于修饰方法,该方法不能被子类重写:
声明类:
final class 类名 {//类体}
声明方法:
修饰符(public/private/default/protected) final 返回值类型 方法名(){//方法体}
注: final 定义的类,其中的属性、方法不是 final 的。
多态
- 多态指同一个实体同时具有多种形式。它是面向对象程序设计(OOP)的一个重要特征。
- 主要是指同一个对象,在不同时刻,代表的对象不一样,指的是对象的多种形态。
- 好处是可以把不同的子类对象都当作父类来看,可以屏蔽不同子类对象之间的差异,写出通用的代码,做出通用的编程,统一调用标准。
特点
1、 多态的前提是继承
2、 要有方法的重写
3、 父类引用指向子类对象,如:Animal a = new Dog(); – 小到大,向上转型
4、 多态中,编译看左边,运行看右边
好处
1、 多态可以让我们不用关心某个对象到底是什么具体类型,就可以使用该对象的某些方法。
2、 提高了程序的扩展性和可维护性
字符串
String 方法
下面是 String 类支持的方法,更多详细,参看 Java String API 文档:
构造方法
构造方法是类的一种特殊方法,用来初始化类的一个新的对象,在创建对象(new 运算符)之后自动调用。Java 中的每个类都有一个默认的构造方法,并且可以有一个以上的构造方法。
Java 构造方法有以下特点:
- 方法名必须与类名相同
- 可以有 0 个、1 个或多个参数
- 没有任何返回值,包括 void
- 默认返回类型就是对象类型本身
- 只能与 new 运算符结合使用
构造方法主要有无参构造方法和有参构造方法两种
示例:
public class MyClass {
private int m; // 定义私有变量
MyClass() {
// 定义无参的构造方法
m = 0;
}
MyClass(int m) {
// 定义有参的构造方法
this.m = m;
}
}
构造函数
Java 中的构造函数是一种用于初始化对象的特殊方法。在创建类的对象时调用构造函数。它可用于设置对象属性的初始值
创建构造函数语法示列如下:
// 创建一个 MyClass 类
public class MyClass {
int x; // 创建类属性
// 为 MyClass 类创建一个类构造函数
public MyClass() {
x = 5; // 设置类属性 x 的初始值
}
public static void main(String[] args) {
MyClass myObj = new MyClass(); // 创建一个 MyClass 类的对象(这将调用构造函数)
System.out.println(myObj.x); // 打印 x 的值
}
}
// 输出 5
注意:
构造函数名称必须与类名匹配,并且不能有返回类型(如 void
).
在创建对象时会调用构造函数。
默认情况下,所有类都有构造函数:如果您自己不创建类构造函数,Java会为您创建一个。但是,您无法设置对象属性的初始值。
方法重载
方法重载(Overloading)的定义:如果有两个方法的方法名相同,但参数不一致,哪么可以说一个方法是另一个方法的重载。 具体说明如下:
- 方法名相同
- 方法的参数类型,参数个不一样
- 方法的返回类型可以不相同
- 方法的修饰符可以不相同
- main 方法也可以被重载
示列:
class MyClass {
int height;
MyClass() {
System.out.println("无参数构造函数");
height = 4;
}
MyClass(int i) {
System.out.println("房子高度为 " + i + " 米");
height = i;
}
void info() {
System.out.println("房子高度为 " + height + " 米");
}
void info(String s) {
System.out.println(s + ": 房子高度为 " + height + " 米");
}
}
public class MainClass {
public static void main(String[] args) {
MyClass t = new MyClass(3);
t.info();
t.info("重载方法");
//重载构造函数
new MyClass();
}
}
输出结果:
房子高度为 3 米
房子高度为 3 米
重载方法: 房子高度为 3 米
无参数构造函数
重写(Override)
重写是子类对父类的允许访问的方法的实现过程进行重新编写, 返回值和形参都不能改变。即外壳不变,核心重写!
重写的好处在于子类可以根据需要,定义特定于自己的行为。 也就是说子类能够根据需要实现父类的方法。
重写方法不能抛出新的检查异常或者比被重写方法申明更加宽泛的异常。例如: 父类的一个方法申明了一个检查异常 IOException,但是在重写这个方法的时候不能抛出 Exception 异常,因为 Exception 是 IOException 的父类,抛出 IOException 异常或者 IOException 的子类异常。
在面向对象原则里,重写意味着可以重写任何现有方法。
示列:
class Animal{
public void move(){
System.out.println("动物可以移动");
}
}
class Dog extends Animal{
public void move(){
System.out.println("狗可以跑和走");
}
}
public class TestDog{
public static void main(String args[]){
Animal a = new Animal(); // Animal 对象
Animal b = new Dog(); // Dog 对象
a.move();// 执行 Animal 类的方法
b.move();//执行 Dog 类的方法
}
}
运行结果:
动物可以移动
狗可以跑和走
在上面的例子中可以看到,尽管 b 属于 Animal 类型,但是它运行的是 Dog 类的 move方法。
这是由于在编译阶段,只是检查参数的引用类型。
然而在运行时,Java 虚拟机(JVM)指定对象的类型并且运行该对象的方法。
因此在上面的例子中,之所以能编译成功,是因为 Animal 类中存在 move 方法,然而运行时,运行的是特定对象的方法。
思考以下例子:
class Animal{
public void move(){
System.out.println("动物可以移动");
}
}
class Dog extends Animal{
public void move(){
System.out.println("狗可以跑和走");
}
public void bark(){
System.out.println("狗可以吠叫");
}
}
public class TestDog{
public static void main(String args[]){
Animal a = new Animal(); // Animal 对象
Animal b = new Dog(); // Dog 对象
a.move();// 执行 Animal 类的方法
b.move();//执行 Dog 类的方法
b.bark();
}
}
运行结果:
TestDog.java:30: cannot find symbol
symbol : method bark()
location: class Animal
b.bark();
^
该程序将抛出一个编译错误,因为b的引用类型Animal没有bark方法。
方法的重写规则
- 参数列表与被重写方法的参数列表必须完全相同。
- 返回类型与被重写方法的返回类型可以不相同,但是必须是父类返回值的派生类(java5 及更早版本返回类型要一样,java7 及更高版本可以不同)。
- 访问权限不能比父类中被重写的方法的访问权限更低。例如:如果父类的一个方法被声明为 public,那么在子类中重写该方法就不能声明为 protected。
- 父类的成员方法只能被它的子类重写。
- 声明为 final 的方法不能被重写。
- 声明为 static 的方法不能被重写,但是能够被再次声明。
- 子类和父类在同一个包中,那么子类可以重写父类所有方法,除了声明为 private 和 final 的方法。
- 子类和父类不在同一个包中,那么子类只能够重写父类的声明为 public 和 protected 的非 final 方法。
- 重写的方法能够抛出任何非强制异常,无论被重写的方法是否抛出异常。但是,重写的方法不能抛出新的强制性异常,或者比被重写方法声明的更广泛的强制性异常,反之则可以。
- 构造方法不能被重写。
- 如果不能继承一个类,则不能重写该类的方法。
异常处理
异常是程序中的一些错误,但并不是所有的错误都是异常,并且错误有时候是可以避免的。
比如说,你的代码少了一个分号,那么运行出来结果是提示是错误 java.lang.Error;如果你用System.out.println(11/0),那么你是因为你用0做了除数,会抛出 java.lang.ArithmeticException 的异常。
异常发生的原因有很多,通常包含以下几大类:
- 用户输入了非法数据。
- 要打开的文件不存在。
- 网络通信时连接中断,或者JVM内存溢出。
这些异常有的是因为用户错误引起,有的是程序错误引起的,还有其它一些是因为物理错误引起的。-
要理解Java异常处理是如何工作的,你需要掌握以下三种类型的异常:
- 检查性异常:最具代表的检查性异常是用户错误或问题引起的异常,这是程序员无法预见的。例如要打开一个不存在文件时,一个异常就发生了,这些异常在编译时不能被简单地忽略。
- 运行时异常: 运行时异常是可能被程序员避免的异常。与检查性异常相反,运行时异常可以在编译时被忽略。
- 错误: 错误不是异常,而是脱离程序员控制的问题。错误在代码中通常被忽略。例如,当栈溢出时,一个错误就发生了,它们在编译也检查不到的。
捕获异常语法:
使用 try 和 catch 关键字可以捕获异常。try/catch 代码块放在异常可能发生的地方。
try/catch代码块中的代码称为保护代码。
try/catch 的语法如下:
try
{
// 程序代码
}catch(ExceptionName e1)
{
//Catch 块
}
Catch 语句包含要捕获异常类型的声明。当保护代码块中发生一个异常时,try 后面的 catch 块就会被检查。
如果发生的异常包含在 catch 块中,异常会被传递到该 catch 块,这和传递一个参数到方法是一样。
多重捕获异常块语法:
一个 try 代码块后面跟随多个 catch 代码块的情况就叫多重捕获。
语法如下:
try{
// 程序代码
}catch(异常类型1 异常的变量名1){
// 程序代码
}catch(异常类型2 异常的变量名2){
// 程序代码
}catch(异常类型3 异常的变量名3){
// 程序代码
}
上面的代码段包含了 3 个 catch块。
可以在 try 语句后面添加任意数量的 catch 块。
如果保护代码中发生异常,异常被抛给第一个 catch 块。
如果抛出异常的数据类型与 ExceptionType1 匹配,它在这里就会被捕获。
如果不匹配,它会被传递给第二个 catch 块。
如此,直到异常被捕获或者通过所有的 catch 块。
Java 内置异常类
ava 语言定义了一些异常类在 java.lang 标准包中。
标准运行时异常类的子类是最常见的异常类。由于 java.lang 包是默认加载到所有的 Java 程序的,所以大部分从运行时异常类继承而来的异常都可以直接使用。
Java 根据各个类库也定义了一些其他的异常,下面的表中列出了 Java 的非检查性异常。
异常 | 描述 |
---|---|
ArithmeticException | 当出现异常的运算条件时,抛出此异常。例如,一个整数"除以零"时,抛出此类的一个实例。 |
ArrayIndexOutOfBoundsException | 用非法索引访问数组时抛出的异常。如果索引为负或大于等于数组大小,则该索引为非法索引。 |
ArrayStoreException | 试图将错误类型的对象存储到一个对象数组时抛出的异常。 |
ClassCastException | 当试图将对象强制转换为不是实例的子类时,抛出该异常。 |
IllegalArgumentException | 抛出的异常表明向方法传递了一个不合法或不正确的参数。 |
IllegalMonitorStateException | 抛出的异常表明某一线程已经试图等待对象的监视器,或者试图通知其他正在等待对象的监视器而本身没有指定监视器的线程。 |
IllegalStateException | 在非法或不适当的时间调用方法时产生的信号。换句话说,即 Java 环境或 Java 应用程序没有处于请求操作所要求的适当状态下。 |
IllegalThreadStateException | 线程没有处于请求操作所要求的适当状态时抛出的异常。 |
IndexOutOfBoundsException | 指示某排序索引(例如对数组、字符串或向量的排序)超出范围时抛出。 |
NegativeArraySizeException | 如果应用程序试图创建大小为负的数组,则抛出该异常。 |
NullPointerException | 当应用程序试图在需要对象的地方使用 null 时,抛出该异常 |
NumberFormatException | 当应用程序试图将字符串转换成一种数值类型,但该字符串不能转换为适当格式时,抛出该异常。 |
SecurityException | 由安全管理器抛出的异常,指示存在安全侵犯。 |
StringIndexOutOfBoundsException | 此异常由 String 方法抛出,指示索引或者为负,或者超出字符串的大小。 |
UnsupportedOperationException | 当不支持请求的操作时,抛出该异常。 |
下面的表中列出了 Java 定义在 java.lang 包中的检查性异常类。
异常 | 描述 |
---|---|
ClassNotFoundException | 应用程序试图加载类时,找不到相应的类,抛出该异常。 |
CloneNotSupportedException | 当调用 Object 类中的 clone 方法克隆对象,但该对象的类无法实现 Cloneable 接口时,抛出该异常。 |
IllegalAccessException | 拒绝访问一个类的时候,抛出该异常。 |
InstantiationException | 当试图使用 Class 类中的 newInstance 方法创建一个类的实例,而指定的类对象因为是一个接口或是一个抽象类而无法实例化时,抛出该异常。 |
InterruptedException | 一个线程被另一个线程中断,抛出该异常。 |
NoSuchFieldException | 请求的变量不存在 |
NoSuchMethodException | 请求的方法不存在 |
异常方法
下面的列表是 Throwable 类的主要方法:
序号 | 方法及说明 |
---|---|
1 | public String getMessage() 返回关于发生的异常的详细信息。这个消息在Throwable 类的构造函数中初始化了。 |
2 | public Throwable getCause() 返回一个 Throwable 对象代表异常原因。 |
3 | public String toString() 返回此 Throwable 的简短描述。 |
4 | public void printStackTrace() 将此 Throwable 及其回溯打印到标准错误流。。 |
5 | public StackTraceElement [] getStackTrace() 返回一个包含堆栈层次的数组。下标为0的元素代表栈顶,最后一个元素代表方法调用堆栈的栈底。 |
6 | public Throwable fillInStackTrace() 用当前的调用栈层次填充Throwable 对象栈层次,添加到栈层次任何先前信息中。 |
集合框架
集合框架被设计成要满足以下几个目标。
- 该框架必须是高性能的。基本集合(动态数组,链表,树,哈希表)的实现也必须是高效的。
- 该框架允许不同类型的集合,以类似的方式工作,具有高度的互操作性。
- 对一个集合的扩展和适应必须是简单的。
为此,整个集合框架就围绕一组标准接口而设计。你可以直接使用这些接口的标准实现,诸如: LinkedList, HashSet, 和 TreeSet 等,除此之外你也可以通过这些接口实现自己的集合。
说明
- 所有集合类都位于 java.util 包下。Java的集合类主要由两个接口派生而出:Collection 和 Map,Collection 和 Map 是 Java 集合框架的根接口,这两个接口又包含了一些子接口或实现类。
- 集合接口:6个接口(短虚线表示),表示不同集合类型,是集合框架的基础。
- 抽象类:5个抽象类(长虚线表示),对集合接口的部分实现。可扩展为自定义集合类。
- 实现类:8个实现类(实线表示),对接口的具体实现。
- Collection 接口是一组允许重复的对象。
- Set 接口继承 Collection,集合元素不重复。
- List 接口继承 Collection,允许重复,维护元素插入顺序。
- Map接口是键-值对象,与Collection接口没有什么关系。
- Set、List 和 Map 可以看做集合的三大类:
List 集合是有序集合,集合中的元素可以重复,访问集合中的元素可以根据元素的索引来访问。
Set 集合是无序集合,集合中的元素不可以重复,访问集合中的元素只能根据元素本身来访问(也是集合里元素不允许重复的原因)。
Map 集合中保存 Key-value 对形式的元素,访问时只能根据每项元素的 key 来访问其 value。
集合框架图如图所示:
Java 集合框架提供了一套性能优良,使用方便的接口和类,java 集合框架位于 java.util 包中, 所以当使用集合框架的时候需要进行导包。
包装类
基本数据类型 | 对应的包装类 |
---|---|
byte | Byte |
char | Char |
int | Integer |
long | Long |
short | Short |
float | Float |
doule | Doule |
boolean | Boolean |
日期时间类
import java.time.*;
import java.util.Calendar;
import java.util.Locale;
public class Example008 {
public static void main(String[] args) {
Clock clock = Clock.systemUTC();
System.out.println("获取UTC时区转换的当前时间"+clock.instant());
System.out.println("获取UTC时区转换的毫秒数"+clock.millis());
Duration duration = Duration.ofDays(1);
System.out.println("一天等于"+ duration.toHours());
System.out.println("一天等于"+duration.toMinutes());
System.out.println("一天等于"+duration.toMillis());
Instant instant = Instant.now();
System.out.println("获取UTC时区的当前时间"+instant);
System.out.println("当前时间一小时后的时间"+instant.plusSeconds(3600));
System.out.println("当前时间一小时前的时间"+instant.minusSeconds(3600));
LocalDate localDate = LocalDate.now();
System.out.println("从默认时区的系统时钟获得的当前日期"+localDate);
LocalTime localTime = LocalTime.now();
System.out.println("从默认时区的系统时钟获取当前时间"+localTime);
LocalDateTime localDateTime = LocalDateTime.now();
System.out.println("从默认时区的系统时钟获取日期,时间"+localDateTime);
LocalDateTime time = localDateTime.plusDays(1).plusHours(3).plusMinutes(30);
System.out.println("当前的日期,时间加上1天3小时30分以后"+time);
Year year = Year.now();
System.out.println("当前年份"+year);
YearMonth yearMonth = YearMonth.now();
System.out.println("当前年月"+yearMonth);
MonthDay monthDay = MonthDay.now();
System.out.println("当前月日"+monthDay);
ZoneId zoneId = ZoneId.systemDefault();
System.out.println("当前系统默认时区为"+zoneId);
}
}
集合接口
集合框架定义了一些接口。本节提供了每个接口的概述:
序号 | 接口描述 |
---|---|
1 | Collection 接口 允许你使用一组对象,是Collection层次结构的根接口。 |
2 | List 接口 继承于Collection和一个 List实例存储一个有序集合的元素。 |
3 | Set 继承于 Collection,是一个不包含重复元素的集合。 |
4 | SortedSet 继承于Set保存有序的集合。 |
5 | Map 将唯一的键映射到值。 |
6 | Map.Entry 描述在一个Map中的一个元素(键/值对)。是一个Map的内部类。 |
7 | SortedMap 继承于Map,使Key保持在升序排列。 |
8 | Enumeration 这是一个传统的接口和定义的方法,通过它可以枚举(一次获得一个)对象集合中的元素。这个传统接口已被迭代器取代。 |
集合类
ava 提供了一套实现了 Collection 接口的标准集合类。其中一些是具体类,这些类可以直接拿来使用,而另外一些是抽象类,提供了接口的部分实现。
标准集合类汇总于下表:
序号 | 类描述 |
---|---|
1 | AbstractCollection 实现了大部分的集合接口。 |
2 | AbstractList 继承于 AbstractCollection 并且实现了大部分List接口。 |
3 | AbstractSequentialList 继承于 AbstractList ,提供了对数据元素的链式访问而不是随机访问。 |
4 | LinkedList 继承于 AbstractSequentialList,实现了一个链表。 |
5 | ArrayList 通过继承 AbstractList,实现动态数组。 |
6 | AbstractSet 继承于 AbstractCollection 并且实现了大部分Set接口。 |
7 | HashSet 继承了 AbstractSet,并且使用一个哈希表。 |
8 | LinkedHashSet 具有可预知迭代顺序的 Set 接口的哈希表和链接列表实现。 |
9 | TreeSet 继承于AbstractSet,使用元素的自然顺序对元素进行排序. |
10 | AbstractMap 实现了大部分的 Map 接口。 |
11 | HashMap 继承了 HashMap,并且使用一个哈希表。 |
12 | TreeMap 继承了 AbstractMap,并且使用一颗树。 |
13 | WeakHashMap 继承 AbstractMap类,使用弱密钥的哈希表。 |
14 | LinkedHashMap 继承于 HashMap,使用元素的自然顺序对元素进行排序. |
15 | IdentityHashMap 继承 AbstractMap 类,比较文档时使用引用相等。 |
在前面的教程中已经讨论通过 java.util 包中定义的类,如下所示:
序号 | 类描述 |
---|---|
1 | Vector Vector 类实现了一个动态数组。和 ArrayList 和相似,但是两者是不同的。 |
2 | Stack 栈是 Vector 的一个子类,它实现了一个标准的后进先出的栈。 |
3 | Dictionary Dictionary 类是一个抽象类,用来存储键/值对,作用和 Map 类相似。 |
4 | Hashtable Hashtable 是原始的 java.util 的一部分, 是一个 Dictionary 具体的实现 。 |
5 | Properties Properties 继承于 Hashtable.表示一个持久的属性集.属性列表中每个键及其对应值都是一个字符串。 |
6 | BitSet 一个 Bitset 类创建一种特殊类型的数组来保存位值。BitSet 中数组大小会随需要增加。 |
一个 Bitset 类创建一种特殊类型的数组来保存位值。BitSet 中数组大小会随需要增加。
集合算法
集合框架定义了几种算法,可用于集合和映射。这些算法被定义为集合类的静态方法。
在尝试比较不兼容的类型时,一些方法能够抛出 ClassCastException
异常。当试图修改一个不可修改的集合时,抛出UnsupportedOperationException
异常。
集合定义三个静态的变量:EMPTY_SET EMPTY_LIST,EMPTY_MAP 的。这些变量都不可改变。
序号 | 算法描述 |
---|---|
1 | Collection Algorithms 这里是一个列表中的所有算法实现。 |
IO流
Java.io 包几乎包含了所有操作输入、输出需要的类。所有这些流类代表了输入源和输出目标。
Java.io 包中的流支持很多种格式,比如:基本类型、对象、本地化字符集等等。
一个流可以理解为一个数据的序列。输入流表示从一个源读取数据,输出流表示向一个目标写数据。
Java 为 I/O 提供了强大的而灵活的支持,使其更广泛地应用到文件传输和网络编程中。
创建文件
package IO;
public class Test {
public static void main(String[] args) {
//创建文件
FileWrite filewrite= new FileWrite();
filewrite.writeTXToFile("D:\\云数据库教程\\a","芜湖");
//读取文件的内容
FileRead fileRead = new FileRead();
fileRead.readTXTfromFile("D:\\云数据库教程\\a");
}
}
写入文件
package IO;
import java.io.*;
public class FileWrite {
/**
* 将文字内容写到文本文件中
* @param filePath 文件路径
* @param txtContext 要写入的文件内容
*/
public static void writeTXToFile(String filePath,String txtContext){
OutputStreamWriter osw = null;
try {
//打开文件输入流(二进制)
FileOutputStream fos = new FileOutputStream(filePath);
//将二进制文件输入流转换成为字符输入流
osw = new OutputStreamWriter(fos);
//将字符串输入到文件
osw.write(txtContext,0,txtContext.length());
//如果文件不存在,则报告错误
}catch (FileNotFoundException e){
e.printStackTrace();
//如果在文件读写的过程中发生错误,则报告错误的原因
}catch (IOException e){
e.printStackTrace();
}finally {
try {
//关闭文件流
if (osw !=null) osw.close();
//如果关闭流的过程中发生错误,则报告错误的原因
}catch (IOException e){
e.printStackTrace();
}
}
}
}
读取文件
package IO;
import java.io.*;
public class FileRead {
/**
* 将文本文件的内容读取出来
* @param filePath 文件路径
*/
public static void readTXTfromFile(String filePath){
BufferedReader br = null;
try {
//打开文件输入流(二进制)
FileInputStream fis = new FileInputStream(filePath);
//将二进制输入流转换成为字符串输入流
InputStreamReader isr = new InputStreamReader(fis);
//使用缓存,提高读出效率
br = new BufferedReader(isr);
String line = null;
while ((line = br.readLine())!=null){
System.out.println(line);
}
}catch (FileNotFoundException e){
e.printStackTrace();
}catch (IOException e){
e.printStackTrace();
}
}
}
读取信息进行删除
package IO;
import java.io.File;
/**
*读取文件信息进行删除
*/
public class FileOperate {
public static void main(String[] args) {
//打开指定路径的文件
File file = new File("D:\\学习\\笔记");
//判断文件是否为目录
if (file.isDirectory()){
File files[] = file.listFiles();
for(File f:files){
System.out.println("文件名称"+f.getName()+"最后修改日期:"+f.lastModified());
}
}
}
}
删除指定文件
package IO;
import java.io.File;
/**
* 删除指定文件
*/
public class FileDelete {
public static void main(String[] args) {
//删除指定路径的文件
File file = new File("D:\\学习\\笔记\\测试");
//判断文件是否存在
if (file.exists()){
//删除文件s
file.delete();
}
}
}
多线程
Java 给多线程编程提供了内置的支持。一个多线程程序包含两个或多个能并发运行的部分。程序的每一部分都称作一个线程,并且每个线程定义了一个独立的执行路径。
多线程是多任务的一种特别的形式。多线程比多任务需要更小的开销。
这里定义和线程相关的另一个术语:进程:一个进程包括由操作系统分配的内存空间,包含一个或多个线程。一个线程不能独立的存在,它必须是进程的一部分。一个进程一直运行,直到所有的非守候线程都结束运行后才能结束。
多线程能满足程序员编写非常有效率的程序来达到充分利用 CPU 的目的,因为 CPU 的空闲时间能够保持在最低限度。
一个线程的生命周期
- 新建(new Thread)
当创建Thread类的一个实例(对象)时,此线程进入新建状态(未被启动)。
例如:Thread t1=new Thread();
- **就绪(runnable)
**线程已经被启动,正在等待被分配给 CPU 时间片,也就是说此时线程正在就绪队列中排队等候得到 CPU 资源。
例如:t1.start();
- **运行(running)
**线程获得 CPU 资源正在执行任务( run() 方法),此时除非此线程自动放弃 CPU 资源或者有优先级更高的线程进入,线程将一直运行到结束。
- 堵塞(blocked)由于某种原因导致正在运行的线程让出CPU并暂停自己的执行,即进入堵塞状态。
正在睡眠:用 sleep(long t) 方法可使线程进入睡眠方式。一个睡眠着的线程在指定的时间过去可进入就绪状态。
正在等待:调用 wait() 方法。(调用 motify() 方法回到就绪状态)
被另一个线程所阻塞:调用 suspend() 方法。(调用 resume() 方法恢复)
- 死亡(dead)当线程执行完毕或被其它线程杀死,线程就进入死亡状态,这时线程不可能再进入就绪状态等待执行。
自然终止:正常运行 run() 方法后终止
异常终止:调用 stop() 方法让一个线程终止运行
java命名规范(驼峰命名法)
为了使代码更加规范使用驼峰命名法来保证代码的可阅读性。
- 包名:多单词组成时所有字每都小写:xxxyyyzzz
- 类名、接口名:多单词组成时,所有单词的首字母大写:XxxYyyZzz(大驼峰命名法)
- 变量名、方法名:多单词组成时,第一个字母的首字母小写,第二个字母开始每个字母首字母大写:xxxYyyZzz(小驼峰命名法)
- 变量名:多单词组成时也可以,所有字母都大写,单词之间用下划线连接:XXX_YYY_ZZZ