序言
序言
Java是一种高级编程语言,最初由Sun Microsystems在1995年发布并在1995年发布。Java运行在各种平台上,如Windows,Mac OS以及各种版本的UNIX。 本教程提供了对Java的完整理解。 学习Java编程语言时,此参考将带您通过简单实用的方法。
本教程已经为初学者准备,以帮助他们理解与Java编程语言相关的基本到高级概念。
在开始练习此参考文献中提供的各种示例之前,我们假设您已经了解计算机程序和计算机编程语言。
简介
Java 简介
Java编程语言最初由Sun Microsystems开发,由James Gosling发起,并于1995年作为Sun Microsystems Java平台(Java 1.0 [J2SE])的核心组件发布。
Java标准版的最新版本是Java SE 8.随着Java的进步和广泛流行,构建了多种配置以适应各种类型的平台。 例如:J2EE for Enterprise Applications,J2ME for Mobile Applications。
新的J2版本分别被重新命名为Java SE,Java EE和Java ME。 Java保证是Write Once,Run Anywhere。
- 面向对象 - 在Java中,一切都是一个对象。 Java可以很容易地扩展,因为它基于Object模型。
- 平台无关 - 与许多其他编程语言(包括C和C ++)不同,编译Java时,不会将其编译到特定于平台的计算机,而是编译为独立于平台的字节码。该字节码分布在Web上,并由虚拟机(JVM)在其运行的任何平台上解释。
- 简单 - Java被设计为易于学习。如果您了解OOP Java的基本概念,则很容易掌握。
- 安全 - 借助Java的安全功能,它可以开发无病毒,无篡改的系统。认证技术基于公钥加密。
- 体系结构中立 - Java编译器生成一个与体系结构无关的目标文件格式,这使得编译后的代码可以在多个处理器上执行,并且具有Java运行时系统。
- 便携式 - 与架构无关并且没有规范的实现依赖方面使Java变得轻松。 Java中的编译器是用ANSI C编写的,具有清晰的可移植边界,这是一个POSIX子集。
- 强大 - Java努力通过强调编译时错误检查和运行时检查来消除容易出错的情况。
- 多线程 - 使用Java的多线程功能,可以编写可同时执行多项任务的程序。这种设计特性允许开发人员构建可以流畅运行的交互式应用程序。
- 解释 - Java字节代码被即时翻译为本地机器指令,并不存储在任何地方。由于链接是一个渐进式和轻量级的过程,所以开发过程更加快速和分析。
- 高性能 - 通过使用实时编译器,Java可实现高性能。
- 分布式 - Java是针对互联网的分布式环境而设计的。
- 动态 - Java被认为比C或C ++更具动态性,因为它旨在适应不断发展的环境。 Java程序可以携带大量的运行时信息,这些信息可用于在运行时验证和解析对对象的访问。
Java的历史
James Gosling于1991年6月发起Java语言项目,用于他的许多机顶盒项目之一。 在Gosling办公室外面的一棵橡树后,最初被称为'橡树'的语言也被命名为'Green',最后被从一系列随机单词中改名为Java。
Sun在1995年发布了第一个Java 1.0公共实现,它承诺编写一次,随处运行(WORA),在流行平台上提供免费运行时间。
2006年11月13日,Sun根据GNU通用公共许可证(GPL)的条款发布了许多Java作为免费和开源软件。
2007年5月8日,Sun完成了这一流程,使Java的所有核心代码免费且开放源代码,除了Sun未拥有版权的一小部分代码之外。
开发工具
为了执行本教程中讨论的示例,您需要至少具有64 MB RAM的Pentium 200-MHz计算机(建议使用128 MB RAM)。
您还需要以下软件 -
- Linux 7.1或Windows XP / 7/8操作系统
- Java JDK 8
- Microsoft记事本或任何其他文本编辑器
本教程将提供使用Java创建GUI,网络和Web应用程序的必要技能。
下一章将指导您如何获取Java及其文档。 最后,它指导您如何安装Java并准备开发Java应用程序的环境。
环境设置
Java 开发环境配置
在本章中,我们将为大家介绍如何搭建Java开发环境。
本地环境设置
如果您仍然愿意为Java编程语言设置您的环境,那么本节将指导您如何在您的机器上下载和设置Java。 以下是设置环境的步骤。
Java SE可以从链接下载Java免费获得。 您可以根据您的操作系统下载一个版本。
按照说明下载Java并运行.exe以在您的机器上安装Java。 一旦你在你的机器上安装了Java,你将需要设置环境变量来指向正确的安装目录 -
为Windows设置路径
假设你已经在c:\ Program Files \ java \ jdk目录中安装了Java -
- 右键单击“我的电脑”并选择“属性”。
- 点击“高级”选项卡下的“环境变量”按钮。
- 现在,改变'Path'变量,以便它也包含Java可执行文件的路径。 例如,如果路径当前设置为'C:\WINDOWS\SYSTEM32',则更改路径为'C:\WINDOWS\SYSTEM32; c:\Program Files\java\jdk\bin'。
为Linux,UNIX,Solaris和FreeBSD设置路径
应将环境变量PATH设置为指向已安装Java二进制文件的位置。 如果您在执行此操作时遇到问题,请参阅您的shell文档。
例如,如果你使用bash作为你的shell,那么你应该在你的'.bashrc: export PATH = /path/to/java:$PATH'。
流行的Java编辑器
要编写Java程序,您需要一个文本编辑器。 市场上还有更复杂的IDE。 但现在,您可以考虑以下其中一项 -
- 记事本 - 在Windows机器上,您可以使用任何简单的文本编辑器,如记事本(推荐用于本教程),TextPad。
- Netbeans - 开源和免费的Java IDE,可从https://www.netbeans.org/index.html下载。
- Eclipse - eclipse开源社区开发的Java IDE,可以从https://www.eclipse.org/下载。
基本语法
Java 基本语法
当我们考虑Java程序时,它可以被定义为通过调用彼此的方法进行通信的对象的集合。 现在让我们简单地看一下类,对象,方法和实例变量的含义。
- 对象 - 对象具有状态和行为。 例如:狗有状态 - 颜色,名称,品种以及行为,如摇尾巴,吠叫,吃东西。 一个对象是一个类的实例。
- 类 - 一个类可以被定义为一个模板/蓝图,描述该类型的对象支持的行为/状态。
- 方法 - 一种方法基本上是一种行为。 一个类可以包含许多方法。 它是在写逻辑的方法中,操纵数据并执行所有操作。
- 实例变量 - 每个对象都有其独特的一组实例变量。 对象的状态由分配给这些实例变量的值创建。
第一个Java程序
让我们看看一个简单的代码,它将打印出Hello World这个词。
例子
public class MyFirstJavaProgram {
/* This is my first java program.
* This will print 'Hello World' as the output
*/
public static void main(String []args) {
System.out.println("Hello World"); // prints Hello World
}
}
我们来看看如何保存文件,编译和运行程序。 请按照后续步骤 -
- 打开记事本并添加上面的代码。
- 将该文件保存为:MyFirstJavaProgram.java。
- 打开一个命令提示符窗口并转到您保存该类的目录。 假设它是C:\。
- 键入'javac MyFirstJavaProgram.java',然后按回车键编译您的代码。 如果代码中没有错误,命令提示符会将您带到下一行(假设:路径变量已设置)。
- 现在,输入'java MyFirstJavaProgram'来运行你的程序。
- 您将能够在窗口上看到“Hello World”。
输出
C:\> javac MyFirstJavaProgram.java C:\> java MyFirstJavaProgram Hello World
基本语法
编写Java程序时,应注意以下几点:
- 大小写敏感:Java是大小写敏感的,这就意味着标识符Hello与hello是不同的。
- 类名:对于所有的类来说,类名的首字母应该大写。如果类名由若干单词组成,那么每个单词的首字母应该大写,例如 MyFirstJavaClass 。
- 方法名:所有的方法名都应该以小写字母开头。如果方法名含有若干单词,则后面的每个单词首字母大写。
- 源文件名:源文件名必须和类名相同。当保存文件的时候,你应该使用类名作为文件名保存(切记Java是大小写敏感的),文件名的后缀为.java。(如果文件名和类名不相同则会导致编译错误)。
- 主方法入口:所有的Java 程序由public static void main(String []args)方法开始执行。
Java标识符
Java所有的组成部分都需要名字。类名、变量名以及方法名都被称为标识符。
关于Java标识符,有以下几点需要注意:
- 所有的标识符都应该以字母(A-Z或者a-z),美元符($)、或者下划线(_)开始
- 首字符之后可以是字母(A-Z或者a-z),美元符($)、下划线(_)或数字的任何字符组合
- 关键字不能用作标识符
- 标识符是大小写敏感的
- 合法标识符举例:age、$salary、_value、__1_value
- 非法标识符举例:123abc、-salary
Java修饰符
像其他语言一样,Java可以使用修饰符来修饰类中方法和属性。主要有两类修饰符:
- 访问控制修饰符 : default, public , protected, private
- 非访问控制修饰符 : final, abstract, strictfp
在后面的章节中我们会深入讨论Java修饰符。
Java变量
Java中主要有如下几种类型的变量
- 局部变量
- 类变量(静态变量)
- 成员变量(非静态变量)
Java数组
数组是储存在堆上的对象,可以保存多个同类型变量。在后面的章节中,我们将会学到如何声明、构造以及初始化一个数组。
Java枚举
Java 5.0引入了枚举,枚举限制变量只能是预先设定好的值。使用枚举可以减少代码中的bug。
例如,我们为果汁店设计一个程序,它将限制果汁为小杯、中杯、大杯。这就意味着它不允许顾客点除了这三种尺寸外的果汁。
例子
class FreshJuice {
enum FreshJuiceSize{ SMALL, MEDIUM, LARGE }
FreshJuiceSize size;
}
public class FreshJuiceTest {
public static void main(String args[]) {
FreshJuice juice = new FreshJuice();
juice.size = FreshJuice.FreshJuiceSize.MEDIUM ;
System.out.println("Size: " + juice.size);
}
}
上面的例子将产生以下的结果
输出
Size: MEDIUM
注意:枚举可以单独声明或者声明在类里面。方法、变量、构造函数也可以在枚举中定义。
Java关键字
以下列表显示了Java中的保留字。 这些保留字不能用作常量或变量或任何其他标识符名称
| abstract | assert | boolean | break |
| byte | case | catch | char |
| class | const | continue | default |
| do | double | else | enum |
| extends | final | finally | float |
| for | goto | if | implements |
| import | instanceof | int | interface |
| long | native | new | package |
| private | protected | public | return |
| short | static | strictfp | super |
| switch | synchronized | this | throw |
| throws | transient | try | void |
| volatile | while |
Java注释
Java支持非常类似于C和C ++的单行和多行注释。 Java编译器会忽略任何注释中可用的所有字符。
例子
public class MyFirstJavaProgram {
/* This is my first java program.
* This will print 'Hello World' as the output
* This is an example of multi-line comments.
*/
public static void main(String []args) {
// This is an example of single line comment
/* This is also an example of single line comment. */
System.out.println("Hello World");
}
}
输出
Hello World
使用空白行
空白行,或者有注释的行,Java编译器都会忽略掉。
继承
在Java中,一个类可以由其他类派生。如果你要创建一个类,而且已经存在一个类具有你所需要的属性或方法,那么你可以将新创建的类继承该类。
利用继承的方法,可以重用已存在类的方法和属性,而不用重写这些代码。被继承的类称为超类(super class),派生类称为子类(subclass)。
接口
在Java中,接口可理解为对象间相互通信的协议。接口在继承中扮演着很重要的角色。
接口只定义派生要用到的方法,但是方法的具体实现完全取决于派生类。
对象和类
Java 对象和类
Java是一种面向对象的语言。 作为一种具有面向对象功能的语言,Java支持以下基本概念 -
- 多态性
- 继承
- 封装
- 抽象
- 类
- 对象
- 实例
- 方法
- 消息解析
在本章中,我们将研究概念 - 类和对象。
- 对象 - 对象具有状态和行为。 例如:狗有状态 - 颜色,名称,品种和行为 - 摇尾巴,吠叫,吃东西。 一个对象是一个类的实例。
- 类 - 类是一个模板,它描述一类对象的行为和状态。
Java中的对象
现在让我们深入研究什么是对象。 如果我们考虑现实世界,我们可以在我们周围发现许多物体,汽车,狗,人等等。所有这些物体都有一个状态和一个行为。
如果我们考虑一只狗,那么它的状态是 - 名称,品种,颜色,行为是 - 吠叫,摇尾巴,跑步。
如果您将软件对象与真实世界的对象进行比较,则它们具有非常相似的特征。
软件对象也有一个状态和一个行为。 软件对象的状态存储在字段中,行为通过方法显示。
因此,在软件开发中,方法根据对象的内部状态进行操作,并且通过方法完成对象到对象的通信。
Java中的类
一个类是创建单个对象的蓝图。
以下是一堂课的样本。
例子
public class Dog {
String breed;
int age;
String color;
void barking() {
}
void hungry() {
}
void sleeping() {
}
}
一个类可以包含以下类型变量:
- 局部变量:在方法、构造方法或者语句块中定义的变量被称为局部变量。变量声明和初始化都是在方法中,方法结束后,变量就会自动销毁。
- 成员变量:成员变量是定义在类中,方法体之外的变量。这种变量在创建对象的时候实例化。成员变量可以被类中方法、构造方法和特定类的语句块访问。
- 类变量:类变量也声明在类中,方法体之外,但必须声明为static类型。
一个类可以拥有多个方法,在上面的例子中:barking()、hungry()和sleeping()都是Dog类的方法。
构造方法
每个类都有构造方法。如果没有显式地为类定义构造方法,Java编译器将会为该类提供一个默认构造方法。
在创建一个对象的时候,至少要调用一个构造方法。构造方法的名称必须与类同名,一个类可以有多个构造方法。
下面是一个构造方法示例:
public class Puppy {
public Puppy() {
}
public Puppy(String name) {
// This constructor has one parameter, name.
}
}
创建对象
对象是根据类创建的。在Java中,使用关键字new来创建一个新的对象。创建对象需要以下三步:
- 声明:声明一个对象,包括对象名称和对象类型。
- 实例化:使用关键字new来创建一个对象。
- 初始化:使用new创建对象时,会调用构造方法初始化对象。
下面是一个创建对象的例子:
public class Puppy {
public Puppy(String name) {
// This constructor has one parameter, name.
System.out.println("Passed Name is :" + name );
}
public static void main(String []args) {
// Following statement would create an object myPuppy
Puppy myPuppy = new Puppy( "tommy" );
}
}
输出
Passed Name is :tommy
访问实例变量和方法
通过已创建的对象来访问成员变量和成员方法,如下所示:
/* First create an object */ ObjectReference = new Constructor(); /* Now call a variable as follows */ ObjectReference.variableName; /* Now you can call a class method as follows */ ObjectReference.MethodName();
例子
这个例子解释了如何访问一个类的实例变量和方法。
public class Puppy {
int puppyAge;
public Puppy(String name) {
// This constructor has one parameter, name.
System.out.println("Name chosen is :" + name );
}
public void setAge( int age ) {
puppyAge = age;
}
public int getAge( ) {
System.out.println("Puppy's age is :" + puppyAge );
return puppyAge;
}
public static void main(String []args) {
/* Object creation */
Puppy myPuppy = new Puppy( "tommy" );
/* Call class method to set puppy's age */
myPuppy.setAge( 2 );
/* Call another class method to get puppy's age */
myPuppy.getAge( );
/* You can access instance variable as follows as well */
System.out.println("Variable Value :" + myPuppy.puppyAge );
}
}
编译并运行上面的程序,产生如下结果:
Name chosen is :tommy Puppy's age is :2 Variable Value :2
源文件声明规则
在本节的最后部分,我们将学习源文件的声明规则。当在一个源文件中定义多个类,并且还有import语句和package语句时,要特别注意这些规则。
- 一个源文件中只能有一个public类
- 一个源文件可以有多个非public类
- 源文件的名称应该和public类的类名保持一致。例如:源文件中public类的类名是Employee,那么源文件应该命名为Employee.java。
- 如果一个类定义在某个包中,那么package语句应该在源文件的首行。
- 如果源文件包含import语句,那么应该放在package语句和类定义之间。如果没有package语句,那么import语句应该在源文件中最前面。
- import语句和package语句对源文件中定义的所有类都有效。在同一源文件中,不能给不同的类不同的包声明。
类有若干种访问级别,并且类也分不同的类型:抽象类和final类等。这些将在访问控制章节介绍。
除了上面提到的几种类型,Java还有一些特殊的类,如:内部类、匿名类。
Java包
包主要用来对类和接口进行分类。当开发Java程序时,可能编写成百上千的类,因此很有必要对类和接口进行分类。
Import语句
在Java中,如果给出一个完整的限定名,包括包名、类名,那么Java编译器就可以很容易地定位到源代码或者类。Import语句就是用来提供一个合理的路径,使得编译器可以找到某个类。
例如,下面的命令行将会命令编译器载入java_installation/java/io路径下的所有类
import java.io.*;
一个简单的例子
在该例子中,我们创建两个类:Employee 和 EmployeeTest。
首先打开文本编辑器,把下面的代码粘贴进去。注意将文件保存为 Employee.java。
Employee类有四个成员变量:name、age、designation和salary。该类显式声明了一个构造方法,该方法只有一个参数。
import java.io.*;
public class Employee {
String name;
int age;
String designation;
double salary;
// This is the constructor of the class Employee
public Employee(String name) {
this.name = name;
}
// Assign the age of the Employee to the variable age.
public void empAge(int empAge) {
age = empAge;
}
/* Assign the designation to the variable designation.*/
public void empDesignation(String empDesig) {
designation = empDesig;
}
/* Assign the salary to the variable salary.*/
public void empSalary(double empSalary) {
salary = empSalary;
}
/* Print the Employee details */
public void printEmployee() {
System.out.println("Name:"+ name );
System.out.println("Age:" + age );
System.out.println("Designation:" + designation );
System.out.println("Salary:" + salary);
}
}
程序都是从main方法开始执行。为了能运行这个程序,必须包含main方法并且创建一个实例对象。
下面给出EmployeeTest类,该类实例化2个 Employee 类的实例,并调用方法设置变量的值。
将下面的代码保存在 EmployeeTest.java文件中。
import java.io.*;
public class EmployeeTest {
public static void main(String args[]) {
/* Create two objects using constructor */
Employee empOne = new Employee("James Smith");
Employee empTwo = new Employee("Mary Anne");
// Invoking methods for each object created
empOne.empAge(26);
empOne.empDesignation("Senior Software Engineer");
empOne.empSalary(1000);
empOne.printEmployee();
empTwo.empAge(21);
empTwo.empDesignation("Software Engineer");
empTwo.empSalary(500);
empTwo.printEmployee();
}
}
编译这两个文件并且运行 EmployeeTest 类,可以看到如下结果:
输出
C:\> javac Employee.java C:\> javac EmployeeTest.java C:\> java EmployeeTest Name:James Smith Age:26 Designation:Senior Software Engineer Salary:1000.0 Name:Mary Anne Age:21 Designation:Software Engineer Salary:500.0
基本数据类型
Java 基本数据类型
变量只是保留内存位置来存储值。 这意味着当你创建一个变量时,你在内存中保留了一些空间。
根据变量的数据类型,操作系统分配内存并决定可以存储在保留内存中的内容。 因此,通过为变量分配不同的数据类型,可以在这些变量中存储整数,小数或字符。
Java中有两种数据类型可用 -
- 内置数据类型
- 引用数据类型
内置数据类型
Java语言提供了八种基本类型。六种数字类型(四个整数型,两个浮点型),一种字符类型,还有一种布尔型。
byte:
- byte 数据类型是8位、有符号的,以二进制补码表示的整数;
- 最小值是-128(-2^7)
- 最大值是127(2^7-1);
- 默认值是0;
- byte 类型用在大型数组中节约空间,主要代替整数,因为 byte 变量占用的空间只有 int 类型的四分之一;
- 例子:byte a = 100,byte b = -50。
short:
- short 数据类型是 16 位、有符号的以二进制补码表示的整数
- 最小值是-32768(-2^15);
- 最大值是32767(2^15 - 1);
- Short 数据类型也可以像 byte 那样节省空间。一个short变量是int型变量所占空间的二分之一;
- 默认值是0;
- 例子:short s = 1000,short r = -20000。
int:
- int 数据类型是32位、有符号的以二进制补码表示的整数;
- 最小值是-2,147,483,648(-2^31);
- 最大值是2,147,483,647(2^31 - 1);
- 一般地整型变量默认为 int 类型;
- 默认值是 0;
- 例子:int a = 100000, int b = -200000。
long:
- long 数据类型是 64 位、有符号的以二进制补码表示的整数;
- 最小值是-9,223,372,036,854,775,808(-2^63);
- 最大值是9,223,372,036,854,775,807(2^63 -1)
- 这种类型主要使用在需要比较大整数的系统上;
- 默认值是 0L;
- 例子: long a = 100000L,Long b = -200000L。
"L"理论上不分大小写,但是若写成"l"容易与数字"1"混淆,不容易分辩。所以最好大写。
float:
- float 数据类型是单精度、32位、符合IEEE 754标准的浮点数;
- float 在储存大型浮点数组的时候可节省内存空间;
- 默认值是 0.0f;
- 浮点数不能用来表示精确的值,如货币;
- 例子:float f1 = 234.5f。
double:
- double 数据类型是双精度、64 位、符合IEEE 754标准的浮点数;
- 浮点数的默认类型为double类型;
- double类型同样不能表示精确的值,如货币;
- 默认值是 0.0d;
- 例子:double d1 = 123.4。
boolean:
- boolean数据类型表示一位的信息;
- 只有两个取值:true 和 false;
- 这种类型只作为一种标志来记录 true/false 情况;
- 默认值是 false;
- 例子:boolean one = true。
char:
- char类型是一个单一的 16 位 Unicode 字符;
- 最小值是 \u0000(即为0);
- 最大值是 \uffff(即为65,535);
- char 数据类型可以储存任何字符;
- 例子:char letter = 'A';
引用类型
- 在Java中,引用类型指向一个对象,指向对象的变量是引用变量。这些变量在声明时被指定为一个特定的类型,比如 Employee、Puppy 等。变量一旦声明后,类型就不能被改变了。
- 对象、数组都是引用数据类型。
- 所有引用类型的默认值都是null。
- 一个引用变量可以用来引用任何与之兼容的类型。
- 例子:Site site = new Site("Runoob")。
Java 常量
常量在程序运行时是不能被修改的。
虽然常量名也可以用小写,但为了便于识别,通常使用大写字母表示常量。
字面量可以赋给任何内置类型的变量。例如:
byte a = 68; char a = 'A'
byte、int、long、和short都可以用十进制、16进制以及8进制的方式来表示。
当使用常量的时候,前缀 0 表示 8 进制,而前缀 0x 代表 16 进制, 例如:
int decimal = 100; int octal = 0144; int hexa = 0x64;
和其他语言一样,Java的字符串常量也是包含在两个引号之间的字符序列。下面是字符串型字面量的例子:
"Hello World" "two\nlines" "\"This is in quotes\""
字符串常量和字符常量都可以包含任何Unicode字符。例如:
char a = '\u0001'; String a = "\u0001";
| 符号 | 字符含义 |
|---|---|
| \n | 换行 (0x0a) |
| \r | 回车 (0x0d) |
| \f | 换页符(0x0c) |
| \b | 退格 (0x08) |
| \0 | 空字符 (0x20) |
| \s | 字符串 |
| \t | 制表符 |
| \" | 双引号 |
| \' | 单引号 |
| \\ | 反斜杠 |
| \ddd | 八进制字符 (ddd) |
| \uxxxx | 16进制Unicode字符 (xxxx) |
变量类型
Java 变量类型
一个变量为我们提供了我们的程序可以操纵的命名存储。 Java中的每个变量都有一个特定的类型,它决定了变量内存的大小和布局; 可以存储在该存储器中的值的范围; 以及可以应用于该变量的一组操作。
您必须先声明所有变量,然后才能使用它们。 以下是变量声明的基本形式 -
data type variable [ = value][, variable [ = value] ...] ;
这里的数据类型是Java的数据类型之一,变量是变量的名称。 要声明指定类型的多个变量,可以使用逗号分隔的列表。
以下是Java中变量声明和初始化的有效示例 -
例子
int a, b, c; // Declares three ints, a, b, and c. int a = 10, b = 10; // Example of initialization byte B = 22; // initializes a byte type variable B. double pi = 3.14159; // declares and assigns a value of PI. char a = 'a'; // the char variable a iis initialized with value 'a'
本章将解释Java语言中可用的各种变量类型。 Java中有三种变量 -
- 局部变量
- 实例变量
- 类/静态变量
局部变量
- 局部变量在方法,构造函数或块中声明。
- 在输入方法,构造函数或块时会创建局部变量,并且一旦变量退出方法,构造函数或块,该变量就会被销毁。
- 访问修饰符不能用于局部变量。
- 局部变量只在声明的方法,构造函数或块中可见。
- 局部变量在内部以堆栈级别实现。
- 局部变量没有默认值,因此应声明局部变量并在首次使用之前分配初始值。
例子
在这里,年龄是一个局部变量。 这是在pupAge()方法内定义的,其范围仅限于此方法。
public class Test {
public void pupAge() {
int age = 0;
age = age + 7;
System.out.println("Puppy age is : " + age);
}
public static void main(String args[]) {
Test test = new Test();
test.pupAge();
}
}
这将产生以下结果 -
Puppy age is: 7
例子
下面的例子没有初始化就使用age,所以在编译时会出现错误。
public class Test {
public void pupAge() {
int age;
age = age + 7;
System.out.println("Puppy age is : " + age);
}
public static void main(String args[]) {
Test test = new Test();
test.pupAge();
}
}
这会在编译时产生以下错误 -
Test.java:4:variable number might not have been initialized age = age + 7; ^ 1 error
实例变量
- 实例变量声明在一个类中,但在方法、构造方法和语句块之外;
- 当一个对象被实例化之后,每个实例变量的值就跟着确定;
- 实例变量在对象创建的时候创建,在对象被销毁的时候销毁;
- 实例变量的值应该至少被一个方法、构造方法或者语句块引用,使得外部能够通过这些方式获取实例变量信息;
- 实例变量可以声明在使用前或者使用后;
- 访问修饰符可以修饰实例变量;
- 实例变量对于类中的方法、构造方法或者语句块是可见的。一般情况下应该把实例变量设为私有。通过使用访问修饰符可以使实例变量对子类可见;
- 实例变量具有默认值。数值型变量的默认值是0,布尔型变量的默认值是false,引用类型变量的默认值是null。变量的值可以在声明时指定,也可以在构造方法中指定;
- 实例变量可以直接通过变量名访问。但在静态方法以及其他类中,就应该使用完全限定名:ObejectReference.VariableName。
例子
import java.io.*;
public class Employee {
// this instance variable is visible for any child class.
public String name;
// salary variable is visible in Employee class only.
private double salary;
// The name variable is assigned in the constructor.
public Employee (String empName) {
name = empName;
}
// The salary variable is assigned a value.
public void setSalary(double empSal) {
salary = empSal;
}
// This method prints the employee details.
public void printEmp() {
System.out.println("name : " + name );
System.out.println("salary :" + salary);
}
public static void main(String args[]) {
Employee empOne = new Employee("Ransika");
empOne.setSalary(1000);
empOne.printEmp();
}
}
这将产生以下结果 -
name : Ransika salary :1000.0
类/静态变量
- 类变量也称为静态变量,在类中以static关键字声明,但必须在方法构造方法和语句块之外。
- 无论一个类创建了多少个对象,类只拥有类变量的一份拷贝。
- 静态变量除了被声明为常量外很少使用。常量是指声明为public/private,final和static类型的变量。常量初始化后不可改变。
- 静态变量储存在静态存储区。经常被声明为常量,很少单独使用static声明变量。
- 静态变量在程序开始时创建,在程序结束时销毁。
- 与实例变量具有相似的可见性。但为了对类的使用者可见,大多数静态变量声明为public类型。
- 默认值和实例变量相似。数值型变量默认值是0,布尔型默认值是false,引用类型默认值是null。变量的值可以在声明的时候指定,也可以在构造方法中指定。此外,静态变量还可以在静态语句块中初始化。
- 静态变量可以通过:ClassName.VariableName的方式访问。
- 类变量被声明为public static final类型时,类变量名称一般建议使用大写字母。如果静态变量不是public和final类型,其命名方式与实例变量以及局部变量的命名方式一致。
例子
import java.io.*;
public class Employee {
// salary variable is a private static variable
private static double salary;
// DEPARTMENT is a constant
public static final String DEPARTMENT = "Development ";
public static void main(String args[]) {
salary = 1000;
System.out.println(DEPARTMENT + "average salary:" + salary);
}
}
这将产生以下结果 -
Development average salary:1000
注意:如果其他类想要访问该变量,可以这样访问:Employee.DEPARTMENT。
修饰符
Java 修饰符
修饰符是您添加到这些定义以更改其含义的关键字。 Java语言有多种修饰符,包括以下内容 -
- Java访问修饰符
- 非访问修饰符
要使用修饰符,可以将其关键字包含在类,方法或变量的定义中。 修饰符在语句的其余部分之前,如下例所示。
public class className {
// ...
}
private boolean myFlag;
static final double weeks = 9.5;
protected static final int BOXWIDTH = 42;
public static void main(String[] arguments) {
// body of method
}
访问控制修饰符
Java中,可以使用访问控制符来保护对类、变量、方法和构造方法的访问。Java 支持 4 种不同的访问权限。
- default (即缺省,什么也不写): 在同一包内可见,不使用任何修饰符。使用对象:类、接口、变量、方法。
- private : 在同一类内可见。使用对象:变量、方法。 注意:不能修饰类(外部类)
- public : 对所有类可见。使用对象:类、接口、变量、方法
- protected : 对同一包内的类和所有子类可见。使用对象:变量、方法。 注意:不能修饰类(外部类)。
默认访问修饰符-不使用任何关键字
使用默认访问修饰符声明的变量和方法,对同一个包内的类是可见的。接口里的变量都隐式声明为 public static final,而接口里的方法默认情况下访问权限为 public。
如下例所示,变量和方法的声明可以不使用任何修饰符。
String version = "1.5.1";
boolean processOrder() {
return true;
}
私有访问修饰符-private
私有访问修饰符是最严格的访问级别,所以被声明为 private 的方法、变量和构造方法只能被所属类访问,并且类和接口不能声明为 private。
声明为私有访问类型的变量只能通过类中公共的 getter 方法被外部类访问。
Private 访问修饰符的使用主要用来隐藏类的实现细节和保护类的数据。
下面的类使用了私有访问修饰符:
public class Logger {
private String format;
public String getFormat() {
return this.format;
}
public void setFormat(String format) {
this.format = format;
}
}
实例中,Logger 类中的 format 变量为私有变量,所以其他类不能直接得到和设置该变量的值。为了使其他类能够操作该变量,定义了两个 public 方法:getFormat() (返回 format的值)和 setFormat(String)(设置 format 的值)
公有访问修饰符-public
被声明为 pub50lic 的类、方法、构造方法和接口能够被任何其他类访问。
如果几个相互访问的 public 类分布在不同的包中,则需要导入相应 public 类所在的包。由于类的继承性,类所有的公有方法和变量都能被其子类继承。
以下函数使用了公有访问控制:
public static void main(String[] arguments) {
// ...
}
Java 程序的 main() 方法必须设置成公有的,否则,Java 解释器将不能运行该类。
受保护的访问修饰符-protected
protected 需要从以下两个点来分析说明:
- 子类与基类在同一包中:被声明为 protected 的变量、方法和构造器能被同一个包中的任何其他类访问;
- 子类与基类不在同一包中:那么在子类中,子类实例可以访问其从基类继承而来的 protected 方法,而不能访问基类实例的protected方法。
protected 访问修饰符不能修饰类和接口,方法和成员变量能够声明为 protected,但是接口的成员变量和成员方法不能声明为 protected。
子类能访问 protected 修饰符声明的方法和变量,这样就能保护不相关的类使用这些方法和变量。
下面的父类使用了 protected 访问修饰符,子类重写了父类的 openSpeaker() 方法。
class AudioPlayer {
protected boolean openSpeaker(Speaker sp) {
// implementation details
}
}
class StreamingAudioPlayer {
boolean openSpeaker(Speaker sp) {
// implementation details
}
}
在这里,如果我们将openSpeaker()方法定义为私有的,那么它将不能从AudioPlayer以外的任何其他类访问。 如果我们把它定义为公开的话,那么它就可以被所有的外部世界所接受。 但是我们的意图是只将这个方法暴露给它的子类,这就是为什么我们使用了protected修饰符。
访问控制和继承
继承方法的以下规则被执行 -
- 在超类中公开的方法也必须在所有子类中公开。
- 在超类中声明保护的方法必须受保护或在子类中公开; 他们不能是私人的。
- 私有的方法根本不会被继承,所以对它们没有规则。
非访问修饰符
为了实现一些其他的功能,Java 也提供了许多非访问修饰符。
- static 修饰符,用来修饰类方法和类变量。
- final 修饰符,用来修饰类、方法和变量,final 修饰的类不能够被继承,修饰的方法不能被继承类重新定义,修饰的变量为常量,是不可修改的。
- abstract 修饰符,用来创建抽象类和抽象方法。
- synchronized 和 volatile 修饰符,主要用于线程的编程。
static 修饰符
静态变量
static关键字用于创建独立于为该类创建的任何实例的变量。 不管类的实例数量如何,只存在一个静态变量副本。
静态变量也称为类变量。 局部变量不能被声明为静态的。
静态方法
static关键字用于创建独立于为该类创建的任何实例的方法。
静态方法不使用任何它们在其中定义的类的任何对象的实例变量。静态方法从参数中获取所有数据,并从这些参数计算出某些内容,而不参考变量。
类变量和方法可以使用类名后面跟一个点和变量或方法的名称来访问。
例子
静态修饰符用于创建类方法和变量,如下例所示 -
public class InstanceCounter {
private static int numInstances = 0;
protected static int getCount() {
return numInstances;
}
private static void addInstance() {
numInstances++;
}
InstanceCounter() {
InstanceCounter.addInstance();
}
public static void main(String[] arguments) {
System.out.println("Starting with " + InstanceCounter.getCount() + " instances");
for (int i = 0; i < 500; ++i) {
new InstanceCounter();
}
System.out.println("Created " + InstanceCounter.getCount() + " instances");
}
}
这将产生以下结果 -
Started with 0 instances Created 500 instances
final 修饰符
final 变量
final 变量能被显式地初始化并且只能初始化一次。被声明为 final 的对象的引用不能指向不同的对象。但是 final 对象里的数据可以被改变。也就是说 final 对象的引用不能改变,但是里面的值可以改变。
final 修饰符通常和 static 修饰符一起使用来创建类常量。
例子
public class Test {
final int value = 10;
// The following are examples of declaring constants:
public static final int BOXWIDTH = 6;
static final String TITLE = "Manager";
public void changeValue() {
value = 12; // will give an error
}
}
final 方法
类中的 final 方法可以被子类继承,但是不能被子类修改。
声明 final 方法的主要目的是防止该方法的内容被修改。
如下所示,使用 final 修饰符声明方法。
public class Test {
public final void changeName() {
// body of method
}
}
final 类
final 类不能被继承,没有类能够继承 final 类的任何特性。
例子
public final class Test {
// body of class
}
abstract 修饰符
抽象类
抽象类永远不能实例化。 如果一个类被声明为抽象的,那么唯一的目的是扩展这个类。
一个类不能既抽象又最终(因为最终的类不能被扩展)。 如果一个类包含抽象方法,那么该类应该被声明为抽象的。 否则,将会抛出一个编译错误。
抽象类可能包含抽象方法和普通方法。
abstract class Caravan {
private double price;
private String model;
private String year;
public abstract void goFast(); // an abstract method
public abstract void changeColor();
}
抽象方法
抽象方法是一种没有任何实现声明的方法。 方法体(实现)由子类提供。 抽象方法永远不可能是最终的或严格的。
任何扩展抽象类的类都必须实现超类的所有抽象方法,除非子类也是一个抽象类。
如果一个类包含一个或多个抽象方法,那么该类必须声明为抽象。 抽象类不需要包含抽象方法。
抽象方法以分号结尾。 例如:public abstract sample();
例子
public abstract class SuperClass {
abstract void m(); // abstract method
}
class SubClass extends SuperClass {
// implements the abstract method
void m() {
.........
}
}
synchronized 修饰符
synchronized关键字用于指示某个方法一次只能由一个线程访问。 同步修饰符可以与四种访问级别修饰符中的任何一种一起应用。
例子
public synchronized void showDetails() {
.......
}
transient 修饰符
序列化的对象包含被 transient 修饰的实例变量时,java 虚拟机(JVM)跳过该特定的变量。
该修饰符包含在定义变量的语句中,用来预处理类和变量的数据类型。
例子
public transient int limit = 55; // will not persist public int b; // will persist
volatile 修饰符
volatile 修饰的成员变量在每次被线程访问时,都强制从共享内存中重新读取该成员变量的值。而且,当成员变量发生变化时,会强制线程将变化值回写到共享内存。这样在任何时刻,两个不同的线程总是看到某个成员变量的同一个值。
一个 volatile 对象引用可能是 null。
例子
public class MyRunnable implements Runnable {
private volatile boolean active;
public void run() {
active = true;
while (active) { // line 1
// some code here
}
}
public void stop() {
active = false; // line 2
}
}
通常情况下,在一个线程调用 run() 方法(在 Runnable 开启的线程),在另一个线程调用 stop() 方法。如果 第一行 中缓冲区的 active 值被使用,那么在 第二行 的 active 值为 false 时循环不会停止。
但是以上代码中我们使用了 volatile 修饰 active,所以该循环会停止。
运算符
Java 运算符
计算机的最基本用途之一就是执行数学运算,作为一门计算机语言,Java也提供了一套丰富的运算符来操纵变量。我们可以把运算符分成以下几组-
- 算术运算符
- 关系运算符
- 位运算符
- 逻辑运算符
- 赋值运算符
- 其他运算符
算术运算符
算术运算符用在数学表达式中,它们的作用和在数学中的作用一样。下表列出了所有的算术运算符。
表格中的实例假设整数变量A的值为10,变量B的值为20 −
| 操作符 | 描述 | 例子 |
|---|---|---|
| +(加) | 加法 - 相加运算符两侧的值. | A + B 等于 30 |
| - (减) | 减法 - 左操作数减去右操作数. | A - B 等于 -10 |
| * (乘) | 乘法 - 相乘操作符两侧的值. | A * B 等于 200 |
| / (除) | 除法 - 左操作数除以右操作数. | B / A 等于 2 |
| % (取模) | 取模 - 左操作数除以右操作数的余数. | B % A 等于 0 |
| ++ (Increment) | 自增: 操作数的值增加1. | B++ 等于 21 |
| -- (Decrement) | 自减: 操作数的值减少1. | B-- 等于 19 |
以下程序是演示算术运算符的简单示例。 将以下Java程序复制并粘贴到Test.java文件中,并编译并运行此程序 -
例子
public class Test {
public static void main(String args[]) {
int a = 10;
int b = 20;
int c = 25;
int d = 25;
System.out.println("a + b = " + (a + b) );
System.out.println("a - b = " + (a - b) );
System.out.println("a * b = " + (a * b) );
System.out.println("b / a = " + (b / a) );
System.out.println("b % a = " + (b % a) );
System.out.println("c % a = " + (c % a) );
System.out.println("a++ = " + (a++) );
System.out.println("b-- = " + (a--) );
// Check the difference in d++ and ++d
System.out.println("d++ = " + (d++) );
System.out.println("++d = " + (++d) );
}
}
这将产生以下结果 -
a + b = 30 a - b = -10 a * b = 200 b / a = 2 b % a = 0 c % a = 5 a++ = 10 b-- = 11 d++ = 25 ++d = 27
关系运算符
下表为Java支持的关系运算符
表格中的实例整数变量A的值为10,变量B的值为20 -
| 操作符 | 描述 | 例子 |
|---|---|---|
| == (等于) | 检查如果两个操作数的值是否相等,如果相等则条件为真. | (A == B) 为假. |
| != (不等于) | 检查如果两个操作数的值是否相等,如果值不相等则条件为真. | (A != B) 为真. |
| > (大于) | 检查左操作数的值是否大于右操作数的值,如果是那么条件为真. | (A > B) 非真. |
| < (小于) | 检查左操作数的值是否小于右操作数的值,如果是那么条件为真. | (A < B) 为真. |
| >= (大于等于) | 检查左操作数的值是否大于或等于右操作数的值,如果是那么条件为真. | (A >= B) 为假. |
| <= (小于等于) | 检查左操作数的值是否小于或等于右操作数的值,如果是那么条件为真. | (A <= B) 为真. |
以下程序是演示关系运算符的简单示例。 将以下Java程序复制并粘贴到Test.java文件中并编译并运行该程序。
例子
public class Test {
public static void main(String args[]) {
int a = 10;
int b = 20;
System.out.println("a == b = " + (a == b) );
System.out.println("a != b = " + (a != b) );
System.out.println("a > b = " + (a > b) );
System.out.println("a < b = " + (a < b) );
System.out.println("b >= a = " + (b >= a) );
System.out.println("b <= a = " + (b <= a) );
}
}
这将产生以下结果 -
a == b = false a != b = true a > b = false a < b = true b >= a = true b <= a = false
位运算符
Java定义了位运算符,应用于整数类型(int),长整型(long),短整型(short),字符型(char),和字节型(byte)等类型。
位运算符作用在所有的位上,并且按位运算。假设a = 60,b = 13;它们的二进制格式表示将如下 -
A = 0011 1100 B = 0000 1101 ----------------- A&b = 0000 1100 A | B = 0011 1101 A ^ B = 0011 0001 ~A= 1100 0011
下表列出了位运算符的基本运算,假设整数变量A的值为60和变量B的值为13 -
| 操作符 | 描述 | 例子 |
|---|---|---|
| & | 如果相对应位都是1,则结果为1,否则为0 | (A&B),得到12,即0000 1100 |
| | | 如果相对应位都是0,则结果为0,否则为1 | (A | B)得到61,即 0011 1101 |
| ^ | 如果相对应位值相同,则结果为0,否则为1 | (A ^ B)得到49,即 0011 0001 |
| 〜 | 按位补运算符翻转操作数的每一位,即0变成1,1变成0。 | (〜A)得到-61,即1100 0011 |
| << | 按位左移运算符。左操作数按位左移右操作数指定的位数。 | A << 2得到240,即 1111 0000 |
| >> | 按位右移运算符。左操作数按位右移右操作数指定的位数。 | A >> 2得到15即 1111 |
| >>> | 按位右移补零操作符。左操作数的值按右操作数指定的位数右移,移动得到的空位以零填充。 | A>>>2得到15即0000 1111 |
以下程序是演示按位运算符的简单示例。 将以下Java程序复制并粘贴到Test.java文件中并编译并运行此程序 -
例子
public class Test {
public static void main(String args[]) {
int a = 60; /* 60 = 0011 1100 */
int b = 13; /* 13 = 0000 1101 */
int c = 0;
c = a & b; /* 12 = 0000 1100 */
System.out.println("a & b = " + c );
c = a | b; /* 61 = 0011 1101 */
System.out.println("a | b = " + c );
c = a ^ b; /* 49 = 0011 0001 */
System.out.println("a ^ b = " + c );
c = ~a; /*-61 = 1100 0011 */
System.out.println("~a = " + c );
c = a << 2; /* 240 = 1111 0000 */
System.out.println("a << 2 = " + c );
c = a >> 2; /* 15 = 1111 */
System.out.println("a >> 2 = " + c );
c = a >>> 2; /* 15 = 0000 1111 */
System.out.println("a >>> 2 = " + c );
}
}
这将产生以下结果 -
a & b = 12 a | b = 61 a ^ b = 49 ~a = -61 a << 2 = 240 a >> 2 = 15 a >>> 2 = 15
逻辑运算符
下表列出了逻辑运算符的基本运算,假设布尔变量A为真,变量B为假
| 操作符 | 描述 | 例子 |
|---|---|---|
| && | 称为逻辑与运算符。当且仅当两个操作数都为真,条件才为真。 | (A && B)为假。 |
| | | | 称为逻辑或操作符。如果任何两个操作数任何一个为真,条件为真。 | (A | | B)为真。 |
| ! | 称为逻辑非运算符。用来反转操作数的逻辑状态。如果条件为true,则逻辑非运算符将得到false。 | !(A && B)为真。 |
下面的简单示例程序演示了逻辑运算符。复制并粘贴下面的Java程序并保存为Test.java文件,然后编译并运行这个程序 -
例子
public class Test {
public static void main(String args[]) {
boolean a = true;
boolean b = false;
System.out.println("a && b = " + (a&&b));
System.out.println("a || b = " + (a||b) );
System.out.println("!(a && b) = " + !(a && b));
}
}
这将产生以下结果 -
a && b = false a || b = true !(a && b) = true
赋值运算符
下面是Java语言支持的赋值运算符 -
| 操作符 | 描述 | 例子 |
|---|---|---|
| = | 简单的赋值运算符,将右操作数的值赋给左侧操作数 | C = A + B将把A + B得到的值赋给C |
| + = | 加和赋值操作符,它把左操作数和右操作数相加赋值给左操作数 | C + = A等价于C = C + A |
| - = | 减和赋值操作符,它把左操作数和右操作数相减赋值给左操作数 | C - = A等价于C = C - A |
| * = | 乘和赋值操作符,它把左操作数和右操作数相乘赋值给左操作数 | C * = A等价于C = C * A |
| / = | 除和赋值操作符,它把左操作数和右操作数相除赋值给左操作数 | C / = A等价于C = C / A |
| (%)= | 取模和赋值操作符,它把左操作数和右操作数取模后赋值给左操作数 | C%= A等价于C = C%A |
| << = | 左移位赋值运算符 | C << = 2等价于C = C << 2 |
| >> = | 右移位赋值运算符 | C >> = 2等价于C = C >> 2 |
| &= | 按位与赋值运算符 | C&= 2等价于C = C&2 |
| ^ = | 按位异或赋值操作符 | C ^ = 2等价于C = C ^ 2 |
| | = | 按位或赋值操作符 | C | = 2等价于C = C | 2 |
以下程序是演示赋值运算符的简单示例。 将以下Java程序复制并粘贴到Test.java文件中。 编译并运行这个程序 -
例子
public class Test {
public static void main(String args[]) {
int a = 10;
int b = 20;
int c = 0;
c = a + b;
System.out.println("c = a + b = " + c );
c += a ;
System.out.println("c += a = " + c );
c -= a ;
System.out.println("c -= a = " + c );
c *= a ;
System.out.println("c *= a = " + c );
a = 10;
c = 15;
c /= a ;
System.out.println("c /= a = " + c );
a = 10;
c = 15;
c %= a ;
System.out.println("c %= a = " + c );
c <<= 2 ;
System.out.println("c <<= 2 = " + c );
c >>= 2 ;
System.out.println("c >>= 2 = " + c );
c >>= 2 ;
System.out.println("c >>= 2 = " + c );
c &= a ;
System.out.println("c &= a = " + c );
c ^= a ;
System.out.println("c ^= a = " + c );
c |= a ;
System.out.println("c |= a = " + c );
}
}
这将产生以下结果 -
c = a + b = 30 c += a = 40 c -= a = 30 c *= a = 300 c /= a = 1 c %= a = 5 c <<= 2 = 20 c >>= 2 = 5 c >>= 2 = 1 c &= a = 0 c ^= a = 10 c |= a = 10
其他运算符
Java语言还支持的其他一些运算符。
条件运算符(?:)
条件运算符也被称为三元运算符。该运算符有3个操作数,并且需要判断布尔表达式的值。该运算符的主要是决定哪个值应该赋值给变量。
variable x = (expression) ? value if true : value if false
例子
public class Test {
public static void main(String args[]) {
int a, b;
a = 10;
b = (a == 1) ? 20: 30;
System.out.println( "Value of b is : " + b );
b = (a == 10) ? 20: 30;
System.out.println( "Value of b is : " + b );
}
}
这将产生以下结果 -
Value of b is : 30 Value of b is : 20
instanceof 运算符
该运算符用于操作对象实例,检查该对象是否是一个特定类型(类类型或接口类型)。
( Object reference variable ) instanceof (class/interface type)
如果运算符左侧变量所指的对象,是操作符右侧类或接口(class/interface)的一个对象,那么结果为真。
例子
public class Test {
public static void main(String args[]) {
String name = "James";
// following will return true since name is type of String
boolean result = name instanceof String;
System.out.println( result );
}
}
这会产生以下结果&minus;
true
如果被比较的对象兼容于右侧类型,该运算符仍然返回true。
class Vehicle {}
public class Car extends Vehicle {
public static void main(String args[]) {
Vehicle a = new Car();
boolean result = a instanceof Car;
System.out.println( result );
}
}
这会产生以下结果&minus;
true
Java运算符优先级
当多个运算符出现在一个表达式中,谁先谁后呢?这就涉及到运算符的优先级别的问题。在一个多运算符的表达式中,运算符优先级不同会导致最后得出的结果差别甚大。
例如,(1+3)+(3+2)*2,这个表达式如果按加号最优先计算,答案就是 18,如果按照乘号最优先,答案则是 14。
再如,x = 7 + 3 * 2;这里x得到13,而不是20,因为乘法运算符比加法运算符有较高的优先级,所以先计算3 * 2得到6,然后再加7。
下表中具有最高优先级的运算符在的表的最上面,最低优先级的在表的底部。
| 类别 | 操作符 | 关联性 |
|---|---|---|
| 后缀 | () [] . (点操作符) | 左到右 |
| 一元 | + + - !〜 | 从右到左 |
| 乘性 | * /% | 左到右 |
| 加性 | + - | 左到右 |
| 移位 | >> >>> << | 左到右 |
| 关系 | >> = << = | 左到右 |
| 相等 | == != | 左到右 |
| 按位与 | & | 左到右 |
| 按位异或 | ^ | 左到右 |
| 按位或 | | | 左到右 |
| 逻辑与 | && | 左到右 |
| 逻辑或 | | | | 左到右 |
| 条件 | ?: | 从右到左 |
| 赋值 | = + = - = * = / =%= >> = << =&= ^ = | = | 从右到左 |
| 逗号 | , | 左到右 |
循环控制
Java 循环控制
当您需要多次执行一段代码时,可能会出现这种情况。 通常,语句按顺序执行:首先执行函数中的第一个语句,然后执行第二个语句,依此类推。
编程语言提供了各种控制结构,允许更复杂的执行路径。
循环语句允许我们多次执行语句或语句组,以下是大多数编程语言中循环语句的一般形式 -
Java编程语言提供以下类型的循环来处理循环要求。
| 序号 | 循环 & 描述 |
|---|---|
| 1 | while 循环 在给定条件为真时重复一个语句或一组语句。 它在执行循环体之前测试条件。 |
| 2 | for 循环 多次执行一系列语句并缩写管理循环变量的代码。 |
| 3 | do...while 循环 像while语句一样,只是它在循环体的末尾测试条件。 |
while 循环
只要给定条件为真,Java编程语言中的while循环语句会重复执行目标语句。
while循环的语法是 -
while(Boolean_expression) {
// Statements
}
在这里,语句可以是单个语句或一组语句。 条件可以是任何表达式,true表示任何非零值。
执行时,如果boolean_expression结果为true,那么循环内的动作将被执行。 只要表达结果为真,这将继续。
当条件变为假时,程序控制传递到循环后面的行。
流程图
在这里,while循环的关键点是循环可能永远不会运行。 当表达式被测试并且结果为false时,循环体将被跳过,while循环之后的第一条语句将被执行。
例子
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
for 循环
for循环是一个重复控制结构,它允许您高效地编写需要执行特定次数的循环。
当你知道一个任务要重复多少次时,for循环很有用。
for循环的语法是
for(initialization; Boolean_expression; update) {
// Statements
}
这是for循环中的控制流程
- 初始化步骤首先执行,并且只执行一次。 此步骤允许您声明和初始化任何循环控制变量,并且此步骤以分号(;)结束。
- 接下来,评估布尔表达式。 如果它是真的,则循环的主体被执行。 如果它为假,循环的主体将不会执行,并且控制跳转到for循环之后的下一个语句。
- 在执行for循环的主体之后,控件跳回到update语句。 这个语句允许你更新任何循环控制变量。 这个声明可以在最后用分号留空。
- 布尔表达式现在再次被评估。 如果它是真的,则循环执行并重复该过程(循环体,然后更新步骤,然后布尔表达式)。 布尔表达式为false后,for循环终止。
流程图
例子
下面是Java中for循环的示例代码。
public class Test {
public static void main(String args[]) {
for(int x = 10; x < 20; x = x + 1) {
System.out.print("value of 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 循环
do ... while循环类似于while循环,除了do ... while循环保证至少执行一次。
以下是do ... while循环的语法 -
do {
// Statements
}while(Boolean_expression);
请注意,布尔表达式出现在循环的结尾,因此循环中的语句在布尔测试之前执行一次。
如果布尔表达式为true,则控制返回执行语句,并且循环中的语句再次执行。 这个过程重复,直到布尔表达式为假。
流程图
例子
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
循环控制语句
循环控制语句从其正常序列中执行。 当执行离开作用域时,在该作用域中创建的所有自动对象都将被销毁。
Java支持以下控制语句。
| 序号 | 控制语句 & 描述 |
|---|---|
| 1 | break 语句 终止循环或切换语句并将执行转移到循环或切换后的语句。 |
| 2 | continue 语句 使循环跳过其正文的其余部分,并在重复之前立即重新测试其条件。 |
break 语句
Java编程语言中的break语句有以下两种用法 -
- 当在循环中遇到break语句时,循环立即终止,程序控制在循环之后的下一个语句处重新开始。
- 它可以用于在switch语句中终止一个case(在下一章中会介绍)。
break语法是任何循环内的单个语句 -
break;
流程图
例子
public class Test {
public static void main(String args[]) {
int [] numbers = {10, 20, 30, 40, 50};
for(int x : numbers ) {
if( x == 30 ) {
break;
}
System.out.print( x );
System.out.print("\n");
}
}
}
这将产生以下结果 −
10 20
continue 语句
continue 适用于任何循环控制结构中。作用是让程序立刻跳转到下一次循环的迭代。
在 for 循环中,continue 语句使程序立即跳转到更新语句。
在 while 或者 do…while 循环中,程序立即跳转到布尔表达式的判断语句。
语法
continue 就是循环体中一条简单的语句
continue;
流程图
例子
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中的增强循环
从Java 5开始,增强的for循环被引入。 这主要用于遍历包含数组的元素的集合。
语法
以下是增强for循环的语法 -
for(declaration : expression) {
// Statements
}
- 声明 - 新声明的块变量的类型与您正在访问的数组元素兼容。 该变量将在for块中可用,其值将与当前数组元素相同。
- 表达式 - 这将评估您需要循环的数组。 该表达式可以是返回数组的数组变量或方法调用。
例子
public class Test {
public static void main(String args[]) {
int [] numbers = {10, 20, 30, 40, 50};
for(int x : numbers ) {
System.out.print( x );
System.out.print(",");
}
System.out.print("\n");
String [] names = {"James", "Larry", "Tom", "Lacy"};
for( String name : names ) {
System.out.print( name );
System.out.print(",");
}
}
}
这将产生以下结果 -
10, 20, 30, 40, 50, James, Larry, Tom, Lacy,
判断
Java 判断
决策制定结构有一个或多个条件需要由程序进行评估或测试,以及如果条件被确定为真时要执行的一个或多个语句,并且可选地在确定条件时执行其他语句 是假的。
以下是大多数编程语言中典型决策结构的一般形式 -
Java编程语言提供以下类型的决策声明。
| 语句 | 描述 |
|---|---|
| if语句 | 一个if语句由一个布尔表达式和一个或多个语句组成。 |
| if...else 语句 | 一个if语句可以跟随一个可选的else语句,当布尔表达式为false时执行该语句。 |
| 嵌套 if 语句 | 您可以在另一个if或else if语句中使用if或else if语句。 |
| switch 语句 | switch语句允许测试一个变量是否与值列表相等。 |
if语句
一个if语句由一个布尔表达式和一个或多个语句组成。
以下是if语句的语法 -
if(Boolean_expression) {
// Statements will execute if the Boolean expression is true
}
如果布尔表达式的计算结果为true,那么将执行if语句内的代码块。 如果不是,则会在if语句结束后(在大括号后)执行第一组代码。
流程图
例子
public class Test {
public static void main(String args[]) {
int x = 10;
if( x < 20 ) {
System.out.print("This is if statement");
}
}
}
这将产生以下结果 −
This is if statement.
if...else 语句
一个if语句可以跟随一个可选的else语句,当布尔表达式为false时执行该语句。
以下是if ... else语句的语法 -
if(Boolean_expression) {
// Executes when the Boolean expression is true
}else {
// Executes when the Boolean expression is false
}
如果布尔表达式的计算结果为true,那么将执行if代码块,否则将执行代码块。
流程图
例子
public class Test {
public static void main(String args[]) {
int x = 30;
if( x < 20 ) {
System.out.print("This is if statement");
} else {
System.out.print("This is else statement");
}
}
}
这将产生以下结果 −
This is else statement
if...else if...else 语句
一个if语句可以跟随一个可选的else if ... else语句,这对使用单个if ... else if语句测试各种条件非常有用。
当使用if,else if,else语句时,有几点需要注意。
- 一个if可以有零个或另一个,它必须在任何其他if之后。
- 一个if可以有零到其他许多if,它们必须在else之前。
- 一旦其他成功,其余的其他if或else都将被测试。
以下是if...if else...else语句的语法 -
if(Boolean_expression 1) {
// Executes when the Boolean expression 1 is true
}else if(Boolean_expression 2) {
// Executes when the Boolean expression 2 is true
}else if(Boolean_expression 3) {
// Executes when the Boolean expression 3 is true
}else {
// Executes when the none of the above condition is 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("This is else statement");
}
}
}
这将产生以下结果 −
Value of X is 30
嵌套 if 语句
嵌套if-else语句总是合法的,这意味着您可以在另一个if或else语句中使用if或else if语句。
嵌套的if ... else的语法如下所示 -
if(Boolean_expression 1) {
// Executes when the Boolean expression 1 is true
if(Boolean_expression 2) {
// Executes when the Boolean expression 2 is true
}
}
你可以嵌套else if ... else,就像我们嵌套if语句一样。
例子
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 语句
switch语句允许测试一个变量是否与值列表相等。 每个值都被称为一个案例,并且检查每个案例中打开的变量。
增强for循环的语法是 -
switch(expression) {
case value :
// Statements
break; // optional
case value :
// Statements
break; // optional
// You can have any number of case statements.
default : // Optional
// Statements
}
以下规则适用于switch语句 -
- switch语句中使用的变量只能是整数,可转换整数(byte,short,char),字符串和枚举。
- switch中可以有任意数量的case语句。每个案例后面跟着要比较的值和一个冒号。
- 案例的值必须与switch中的变量具有相同的数据类型,并且它必须是常量或文字。
- 当接通的变量等于一个case时,这个case后面的语句将会执行,直到到达break语句。
- 当达到break语句时,开关终止,并且控制流程跳转到switch语句后面的下一行。
- 并非所有情况下都需要包含break。如果没有break,则控制流程将落入后续案例,直至达到一个break。
- switch语句可以有一个可选的默认情况,它必须出现在交换机的末尾。如果没有任何一种情况属实,默认情况下可用于执行任务。默认情况下不需要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("Excellent!");
break;
case 'B' :
case 'C' :
System.out.println("Well done");
break;
case 'D' :
System.out.println("You passed");
case 'F' :
System.out.println("Better try again");
break;
default :
System.out.println("Invalid grade");
}
System.out.println("Your grade is " + grade);
}
}
编译并运行上述程序。 这将产生以下结果 -
Well done Your grade is C
? : 运算符(三元运算符)
我们已经在前面的章节中讲解了 条件运算符 ? :,可以用来替代 if...else 语句。它的一般形式如下:
Exp1 ? Exp2 : Exp3;
其中,Exp1、Exp2 和 Exp3 是表达式。请注意,冒号的使用和位置。
? 表达式的值是由 Exp1 决定的。如果 Exp1 为真,则计算 Exp2 的值,结果即为整个 ? 表达式的值。如果 Exp1 为假,则计算 Exp3 的值,结果即为整个 ? 表达式的值。
为了确定整个表达式的值,首先评估exp1。
- 如果exp1的值为真,则Exp2的值将是整个表达式的值。
- 如果exp1的值为false,则评估Exp3并将其值变为整个表达式的值。
Numbers类
Java - Numbers类
通常,当我们使用Numbers时,我们使用诸如byte,int,long,double等原始数据类型。
例子
int i = 5000; float gpa = 13.65; double mask = 0xaf;
但是,在开发过程中,我们遇到了需要使用对象而不是基本数据类型的情况。 为了实现这一点,Java提供了包装类。
所有包装类(整型,长型,字节型,双精度型,浮点型,短型)都是抽象类Number的子类。
包装类的对象包含或包装其各自的原始数据类型。 将原始数据类型转换为对象称为装箱,这由编译器负责。 因此,在使用包装类时,您只需将基元数据类型的值传递给Wrapper类的构造函数即可。
并且Wrapper对象将被转换回原始数据类型,并且这个过程被称为拆箱。 Number类是java.lang包的一部分。
以下是装箱和拆箱的例子 -
public class Test {
public static void main(String args[]) {
Integer x = 5; // boxes int to an Integer object
x = x + 10; // unboxes the Integer to a int
System.out.println(x);
}
}
这将产生以下结果 −
15
当x被分配一个整数值时,编译器会将该整数装箱,因为x是整数对象。 稍后,x将被拆箱,以便它们可以作为整数添加。
Number方法
以下是Number类的所有子类实现的实例方法的列表 -
| 序号 | 方法 & 描述 |
|---|---|
| 1 | xxxValue() 将 Number 对象转换为xxx数据类型的值并返回。 |
| 2 | compareTo() 将number对象与参数比较。 |
| 3 | equals() 判断number对象是否与参数相等。 |
| 4 | valueOf() 返回一个 Number 对象指定的内置数据类型 |
| 5 | toString() 以字符串形式返回值。 |
| 6 | parseInt() 将字符串解析为int类型。 |
| 7 | abs() 返回参数的绝对值。 |
| 8 | ceil() 返回大于等于( >= )给定参数的的最小整数。 |
| 9 | floor() 返回小于等于(<=)给定参数的最大整数 。 |
| 10 | rint() 返回与参数最接近的整数。返回类型为double。 |
| 11 | round() 它表示四舍五入,算法为 Math.floor(x+0.5),即将原来的数字加上 0.5 后再向下取整,所以,Math.round(11.5) 的结果为12,Math.round(-11.5) 的结果为-11。 |
| 12 | min() 返回两个参数中的最小值。 |
| 13 | max() 返回两个参数中的最大值。 |
| 14 | exp() 返回自然数底数e的参数次方。 |
| 15 | log() 返回参数的自然数底数的对数值。 |
| 16 | pow() 返回第一个参数的第二个参数次方。 |
| 17 | sqrt() 求参数的算术平方根。 |
| 18 | sin() 求指定double类型参数的正弦值。 |
| 19 | cos() 求指定double类型参数的余弦值。 |
| 20 | tan() 求指定double类型参数的正切值。 |
| 21 | asin() 求指定double类型参数的反正弦值。 |
| 22 | acos() 求指定double类型参数的反余弦值。 |
| 23 | atan() 求指定double类型参数的反正切值。 |
| 24 | atan2() 将笛卡尔坐标转换为极坐标,并返回极坐标的角度值。 |
| 25 | toDegrees() 将参数转化为角度。 |
| 26 | toRadians() 将角度转换为弧度。 |
| 27 | random() 返回一个随机数。 |
xxxValue() 方法
描述
该方法将调用方法的Number对象的值转换为从该方法返回的基本数据类型。
语法
这是每种基本数据类型的单独方法 -
byte byteValue() short shortValue() int intValue() long longValue() float floatValue() double doubleValue()
参数
这里是参数的细节 -
- 所有这些都是默认方法并且不接受任何参数。
返回值
- 此方法返回签名中给出的原始数据类型。
例子
public class Test {
public static void main(String args[]) {
Integer x = 5;
// Returns byte primitive data type
System.out.println( x.byteValue() );
// Returns double primitive data type
System.out.println(x.doubleValue());
// Returns long primitive data type
System.out.println( x.longValue() );
}
}
这将产生以下结果 -
5 5.0 5
compareTo() 方法
compareTo() 方法用于将 Number 对象与方法的参数进行比较。可用于比较 Byte, Long, Integer等。
该方法用于两个相同数据类型的比较,两个不同类型的数据不能用此方法来比较。
语法
public int compareTo( NumberSubClass referenceName )
参数
referenceName -- 可以是一个 Byte, Double, Integer, Float, Long 或 Short 类型的参数。
返回值
- 如果指定的数与参数相等返回0。
- 如果指定的数小于参数返回 -1。
- 如果指定的数大于参数返回 1。
例子
public class Test {
public static void main(String args[]) {
Integer x = 5;
System.out.println(x.compareTo(3));
System.out.println(x.compareTo(5));
System.out.println(x.compareTo(8));
}
}
这将产生以下结果 -
1 0 -1
equals() 方法
equals() 方法用于判断 Number 对象与方法的参数进是否相等。
语法
public boolean equals(Object o)
参数
-- 任何对象。
返回值
如果参数不是null并且是具有相同类型和相同数值的对象,则该方法返回True。 对于Java API文档中描述的Double和Float对象有一些额外的要求。
实例
public class Test {
public static void main(String args[]) {
Integer x = 5;
Integer y = 10;
Integer z =5;
Short a = 5;
System.out.println(x.equals(y));
System.out.println(x.equals(z));
System.out.println(x.equals(a));
}
}
编译以上程序,输出结果为:
false true false
Character类
Java Character 类
通常,当我们使用字符时,我们使用原始数据类型char。
例子
char ch = 'a';
// Unicode for uppercase Greek omega character
char uniChar = '\u039A';
// an array of chars
char[] charArray ={ 'a', 'b', 'c', 'd', 'e' };
然而在开发中,我们遇到了需要使用对象而不是基本数据类型的情况。 为了实现这一点,Java为原始数据类型char提供了包装类Character。
Character类提供了许多有用的类(即静态)方法来处理字符。 您可以使用Character构造函数创建Character对象 -
Character ch = new Character('a');
在某些情况下,Java编译器也会为您创建一个Character对象。 例如,如果您将一个原始字符传递给期望对象的方法,编译器会自动将该字符转换为一个字符。 如果转换以其他方式进行,此功能称为自动装箱或取消装箱。
例子
// Here following primitive char 'a'
// is boxed into the Character object ch
Character ch = 'a';
// Here primitive 'x' is boxed for method test,
// return is unboxed to char 'c'
char c = test('x');
转义序列
以反斜杠(\)开头的字符是转义序列,对编译器有特殊意义。
在本教程中,换行符(\ n)在System.out.println()语句中经常用于在打印字符串之后前进到下一行。
下表显示了Java转义序列 -
| 转义序列 | 描述 |
|---|---|
| \t | 在文中该处插入一个tab键 |
| \b | 在文中该处插入一个后退键 |
| \n | 在文中该处换行 |
| \r | 在文中该处插入回车 |
| \f | 在文中该处插入换页符 |
| \' | 在文中该处插入单引号 |
| \" | 在文中该处插入双引号 |
| \\ | 在文中该处插入反斜杠 |
当在打印语句中遇到转义序列时,编译器会相应地解释它。
例子
如果你想把引号放在引号内,你必须在内部引号上使用转义序列\“,
public class Test {
public static void main(String args[]) {
System.out.println("She said \"Hello!\" to me.");
}
}
这将产生以下结果 −
She said "Hello!" to me.
Character 方法
下面是Character类的方法 -
| b序号 | b方法与描述 |
|---|---|
| 1 | isLetter() 是否是一个字母 |
| 2 | isDigit() 是否是一个数字字符 |
| 3 | isWhitespace() 是否是一个空格 |
| 4 | isUpperCase() 是否是大写字母 |
| 5 | isLowerCase() 是否是小写字母 |
| 6 | toUpperCase() 指定字母的大写形式 |
| 7 | toLowerCase() 指定字母的小写形式 |
| 8 | toString() 返回字符的字符串形式,字符串的长度仅为1 |
有关方法的完整列表,请参阅java.lang.Character API规范。
Stirng类
Java String 类
在Java编程中广泛使用的字符串是一系列字符。 在Java编程语言中,字符串被视为对象。
Java平台提供了String类来创建和操作字符串。
创建字符串
创建字符串最直接的方法是编写 -
String greeting = "Hello world!";
只要遇到代码中的字符串文字,编译器就会在这种情况下创建一个字符串对象“Hello world!”。
与任何其他对象一样,您可以使用new关键字和构造函数创建String对象。 String类有11个构造函数,它们允许您使用不同的来源(如字符数组)提供字符串的初始值。
例子
public class StringDemo {
public static void main(String args[]) {
char[] helloArray = { 'h', 'e', 'l', 'l', 'o', '.' };
String helloString = new String(helloArray);
System.out.println( helloString );
}
}
这将产生以下结果 −
hello.
注 − String类是不可变的,所以一旦创建了String对象就不能改变。 如果需要对字符串进行大量修改,则应使用字符串缓冲区和字符串生成器类。
字符串长度
用于获取关于对象的信息的方法被称为访问器方法。 一个可以用于字符串的存取方法是length()方法,它返回字符串对象中包含的字符数。
以下程序是length()方法String类的一个示例。
例子
public class StringDemo {
public static void main(String args[]) {
String palindrome = "Dot saw I was Tod";
int len = palindrome.length();
System.out.println( "String Length is : " + len );
}
}
这将产生以下结果 −
String Length is : 17
连接字符串
String类包含一个连接两个字符串的方法 −
string1.concat(string2);
这将返回一个新的字符串,该字符串是string1,并在末尾添加了string2。 您也可以使用字符串文字的concat()方法,如 −
"My name is ".concat("Zara");
字符串通常与+运算符连接在一起, −
"Hello," + " world" + "!"
这导致了 −
"Hello, world!"
让我们看看下面的例子 −
例子
public class StringDemo {
public static void main(String args[]) {
String string1 = "saw I was ";
System.out.println("Dot " + string1 + "Tod");
}
}
这将产生以下结果 −
Dot saw I was Tod
创建格式字符串
你有printf()和format()方法来打印带格式数字的输出。 String类有一个等效的类方法format(),它返回一个String对象而不是一个PrintStream对象。
使用String的静态格式()方法可以创建可以重用的格式化字符串,而不是一次性打印语句。 例如,而不是 -
例子
System.out.printf("The value of the float variable is " +
"%f, while the value of the integer " +
"variable is %d, and the string " +
"is %s", floatVar, intVar, stringVar);
你可以写 −
String fs;
fs = String.format("The value of the float variable is " +
"%f, while the value of the integer " +
"variable is %d, and the string " +
"is %s", floatVar, intVar, stringVar);
System.out.println(fs);
字符串方法
这里是String类支持的方法列表 -
| SN(序号) | 方法描述 |
|---|---|
| 1 | char charAt(int index) 返回指定索引处的 char 值。 |
| 2 | int compareTo(Object o) 把这个字符串和另一个对象比较。 |
| 3 | int compareTo(String anotherString) 按字典顺序比较两个字符串。 |
| 4 | int compareToIgnoreCase(String str) 按字典顺序比较两个字符串,不考虑大小写。 |
| 5 | String concat(String str) 将指定字符串连接到此字符串的结尾。 |
| 6 | boolean contentEquals(StringBuffer sb) 当且仅当字符串与指定的StringBuffer有相同顺序的字符时候返回真。 |
| 7 | static String copyValueOf(char[] data) 返回指定数组中表示该字符序列的 String。 |
| 8 | static String copyValueOf(char[] data, int offset, int count) 返回指定数组中表示该字符序列的 String。 |
| 9 | boolean endsWith(String suffix) 测试此字符串是否以指定的后缀结束。 |
| 10 | boolean equals(Object anObject) 将此字符串与指定的对象比较。 |
| 11 | boolean equalsIgnoreCase(String anotherString) 将此 String 与另一个 String 比较,不考虑大小写。 |
| 12 | byte[] getBytes() 使用平台的默认字符集将此 String 编码为 byte 序列,并将结果存储到一个新的 byte 数组中。 |
| 13 | byte[] getBytes(String charsetName) 使用指定的字符集将此 String 编码为 byte 序列,并将结果存储到一个新的 byte 数组中。 |
| 14 | void getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin) 将字符从此字符串复制到目标字符数组。 |
| 15 | int hashCode() 返回此字符串的哈希码。 |
| 16 | int indexOf(int ch) 返回指定字符在此字符串中第一次出现处的索引。 |
| 17 | int indexOf(int ch, int fromIndex) 返回在此字符串中第一次出现指定字符处的索引,从指定的索引开始搜索。 |
| 18 | int indexOf(String str) 返回指定子字符串在此字符串中第一次出现处的索引。 |
| 19 | int indexOf(String str, int fromIndex) 返回指定子字符串在此字符串中第一次出现处的索引,从指定的索引开始。 |
| 20 | String intern() 返回字符串对象的规范化表示形式。 |
| 21 | int lastIndexOf(int ch) 返回指定字符在此字符串中最后一次出现处的索引。 |
| 22 | int lastIndexOf(int ch, int fromIndex) 返回指定字符在此字符串中最后一次出现处的索引,从指定的索引处开始进行反向搜索。 |
| 23 | int lastIndexOf(String str) 返回指定子字符串在此字符串中最右边出现处的索引。 |
| 24 | int lastIndexOf(String str, int fromIndex) 返回指定子字符串在此字符串中最后一次出现处的索引,从指定的索引开始反向搜索。 |
| 25 | int length() 返回此字符串的长度。 |
| 26 | boolean matches(String regex) 告知此字符串是否匹配给定的正则表达式。 |
| 27 | boolean regionMatches(boolean ignoreCase, int toffset, String other, int ooffset, int len) 测试两个字符串区域是否相等。 |
| 28 | boolean regionMatches(int toffset, String other, int ooffset, int len) 测试两个字符串区域是否相等。 |
| 29 | String replace(char oldChar, char newChar) 返回一个新的字符串,它是通过用 newChar 替换此字符串中出现的所有 oldChar 得到的。 |
| 30 | String replaceAll(String regex, String replacement) 使用给定的 replacement 替换此字符串所有匹配给定的正则表达式的子字符串。 |
| 31 | String replaceFirst(String regex, String replacement) 使用给定的 replacement 替换此字符串匹配给定的正则表达式的第一个子字符串。 |
| 32 | String[] split(String regex) 根据给定正则表达式的匹配拆分此字符串。 |
| 33 | String[] split(String regex, int limit) 根据匹配给定的正则表达式来拆分此字符串。 |
| 34 | boolean startsWith(String prefix) 测试此字符串是否以指定的前缀开始。 |
| 35 | boolean startsWith(String prefix, int toffset) 测试此字符串从指定索引开始的子字符串是否以指定前缀开始。 |
| 36 | CharSequence subSequence(int beginIndex, int endIndex) 返回一个新的字符序列,它是此序列的一个子序列。 |
| 37 | String substring(int beginIndex) 返回一个新的字符串,它是此字符串的一个子字符串。 |
| 38 | String substring(int beginIndex, int endIndex) 返回一个新字符串,它是此字符串的一个子字符串。 |
| 39 | char[] toCharArray() 将此字符串转换为一个新的字符数组。 |
| 40 | String toLowerCase() 使用默认语言环境的规则将此 String 中的所有字符都转换为小写。 |
| 41 | String toLowerCase(Locale locale) 使用给定 Locale 的规则将此 String 中的所有字符都转换为小写。 |
| 42 | String toString() 返回此对象本身(它已经是一个字符串!)。 |
| 43 | String toUpperCase() 使用默认语言环境的规则将此 String 中的所有字符都转换为大写。 |
| 44 | String toUpperCase(Locale locale) 使用给定 Locale 的规则将此 String 中的所有字符都转换为大写。 |
| 45 | String trim() 返回字符串的副本,忽略前导空白和尾部空白。 |
| 46 | static String valueOf(primitive data type x) 返回给定data type类型x参数的字符串表示形式。 |
String Buffer and String Builder类
当需要对字符串进行大量修改时,使用StringBuffer和StringBuilder类。
与字符串不同,StringBuffer和String构建器类型的对象可以一遍又一遍地修改,而不会留下很多新的未使用的对象。
StringBuilder类是从Java 5开始引入的,StringBuffer和StringBuilder的主要区别在于StringBuilders方法不是线程安全的(不同步)。
建议尽可能使用StringBuilder,因为它比StringBuffer快。 但是,如果线程安全是必要的,最好的选择是StringBuffer对象。
例子
public class Test {
public static void main(String args[]) {
StringBuffer sBuffer = new StringBuffer("test");
sBuffer.append(" String Buffer");
System.out.println(sBuffer);
}
}
这将产生一下结果 −
test String Buffer
StringBuffer 方法
以下是 StringBuffer 类支持的主要方法 -
| 序号 | 方法描述 |
|---|---|
| 1 | public StringBuffer append(String s) 将指定的字符串追加到此字符序列。 |
| 2 | public StringBuffer reverse() 将此字符序列用其反转形式取代。 |
| 3 | public delete(int start, int end) 移除此序列的子字符串中的字符。 |
| 4 | public insert(int offset, int i) 将 int 参数的字符串表示形式插入此序列中。 |
| 5 | replace(int start, int end, String str) 使用给定 String 中的字符替换此序列的子字符串中的字符。 |
下面的列表里的方法和 String 类的方法类似 -
| 序号 | 方法描述 |
|---|---|
| 1 | int capacity() 返回当前容量。 |
| 2 | char charAt(int index) 返回此序列中指定索引处的 char 值。 |
| 3 | void ensureCapacity(int minimumCapacity) 确保容量至少等于指定的最小值。 |
| 4 | void getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin) 将字符从此序列复制到目标字符数组 dst。 |
| 5 | int indexOf(String str) 返回第一次出现的指定子字符串在该字符串中的索引。 |
| 6 | int indexOf(String str, int fromIndex) 从指定的索引处开始,返回第一次出现的指定子字符串在该字符串中的索引。 |
| 7 | int lastIndexOf(String str) 返回最右边出现的指定子字符串在此字符串中的索引。 |
| 8 | int lastIndexOf(String str, int fromIndex) 返回 String 对象中子字符串最后出现的位置。 |
| 9 | int length() 返回长度(字符数)。 |
| 10 | void setCharAt(int index, char ch) 将给定索引处的字符设置为 ch。 |
| 11 | void setLength(int newLength) 设置字符序列的长度。 |
| 12 | CharSequence subSequence(int start, int end) 返回一个新的字符序列,该字符序列是此序列的子序列。 |
| 13 | String substring(int start) 返回一个新的 String,它包含此字符序列当前所包含的字符子序列。 |
| 14 | String substring(int start, int end) 返回一个新的 String,它包含此序列当前所包含的字符子序列。 |
| 15 | String toString() 返回此序列中数据的字符串表示形式。 |
数组
Java 数组
Java提供了一个数据结构,该数组存储相同类型元素的固定大小的顺序集合。 数组用于存储数据集合,但将数组视为相同类型的变量集合通常更有用。
您不需要声明单个变量,如number0,number1,...和number99,而是声明一个数组变量,如数字和使用数字[0],数字[1]和...,数字[99]来表示 个体变量。
本教程介绍了如何声明数组变量,创建数组和使用索引变量处理数组。
声明数组变量
要在程序中使用数组,必须声明一个变量来引用该数组,并且必须指定该变量可以引用的数组的类型。 这里是声明一个数组变量的语法 -
语法
dataType[] arrayRefVar; // preferred way. or dataType arrayRefVar[]; // works but not preferred way.
注 - 样式dataType [] arrayRefVar是首选。 样式dataType arrayRefVar []来自C / C ++语言,并被Java采纳以适应C / C ++程序员。
例子
以下代码片段是此语法的示例 -
double[] myList; // preferred way. or double myList[]; // works but not preferred way.
创建数组
您可以通过使用以下语法使用新运算符来创建一个数组 -
语法
arrayRefVar = new dataType[arraySize];
上面的语法语句做了两件事 -
- 一、使用 dataType[arraySize] 创建了一个数组。
- 二、把新创建的数组的引用赋值给变量 arrayRefVar。
数组变量的声明,和创建数组可以用一条语句完成,如下所示 -
dataType[] arrayRefVar = new dataType[arraySize];
另外,你还可以使用如下的方式创建数组。
dataType[] arrayRefVar = {value0, value1, ..., valuek};
数组的元素是通过索引访问的。数组索引从 0 开始,所以索引值从 0 到 arrayRefVar.length-1。
例子
下面的语句首先声明了一个数组变量 myList,接着创建了一个包含 10 个 double 类型元素的数组,并且把它的引用赋值给 myList 变量。
double[] myList = new double[10];
下面的图片代表数组myList。 在这里,myList包含十个double值,索引从0到9.
访问数组
访问数组元素时,我们经常使用for循环或foreach循环,因为数组中的所有元素都是相同类型,并且数组的大小已知。
例子
这里是一个完整的例子,展示了如何创建,初始化和处理数组 -
public class TestArray {
public static void main(String[] args) {
double[] myList = {1.9, 2.9, 3.4, 3.5};
// Print all the array elements
for (int i = 0; i < myList.length; i++) {
System.out.println(myList[i] + " ");
}
// Summing all elements
double total = 0;
for (int i = 0; i < myList.length; i++) {
total += myList[i];
}
System.out.println("Total is " + total);
// Finding the largest element
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
foreach 循环
JDK 1.5引入了一个新的for循环,称为foreach循环或增强for循环,使您可以在不使用索引变量的情况下顺序遍历整个数组。
例子
以下代码显示数组myList中的所有元素 -
public class TestArray {
public static void main(String[] args) {
double[] myList = {1.9, 2.9, 3.4, 3.5};
// Print all the array elements
for (double element: myList) {
System.out.println(element);
}
}
}
这将产生以下结果 −
1.9 2.9 3.4 3.5
将数组传递给方法
就像您可以将原始类型值传递给方法一样,您也可以将数组传递给方法。 例如,以下方法在int数组中显示元素 -
例子
public static void printArray(int[] array) {
for (int i = 0; i < array.length; i++) {
System.out.print(array[i] + " ");
}
}
你可以通过传递一个数组来调用它。 例如,以下语句调用printArray方法来显示3,1,2,6,4和2 -
例子
printArray(new int[]{3, 1, 2, 6, 4, 2});
从方法返回数组
一个方法也可以返回一个数组。 例如,下面的方法返回一个数组,它是另一个数组的反转 -
例子
public static int[] reverse(int[] list) {
int[] result = new int[list.length];
for (int i = 0, j = result.length - 1; i < list.length; i++, j--) {
result[j] = list[i];
}
return result;
}
Arrays 类
java.util.Arrays类包含各种静态方法,用于排序和搜索数组,比较数组和填充数组元素。 这些方法对于所有基元类型都是重载的
| 序号 | 方法和说明 |
|---|---|
| 1 | public static int binarySearch(Object[] a, Object key) 用二分查找算法在给定数组中搜索给定值的对象(Byte,Int,double等)。数组在调用前必须排序好的。如果查找值包含在数组中,则返回搜索键的索引;否则返回 (-(插入点) - 1)。 |
| 2 | public static boolean equals(long[] a, long[] a2) 如果两个指定的 long 型数组彼此相等,则返回 true。如果两个数组包含相同数量的元素,并且两个数组中的所有相应元素对都是相等的,则认为这两个数组是相等的。换句话说,如果两个数组以相同顺序包含相同的元素,则两个数组是相等的。同样的方法适用于所有的其他基本数据类型(Byte,short,Int等)。 |
| 3 | public static void fill(int[] a, int val) 将指定的 int 值分配给指定 int 型数组指定范围中的每个元素。同样的方法适用于所有的其他基本数据类型(Byte,short,Int等)。 |
| 4 | public static void sort(Object[] a) 对指定对象数组根据其元素的自然顺序进行升序排列。同样的方法适用于所有的其他基本数据类型(Byte,short,Int等)。 |
日期和时间
Java 日期时间
Java提供了java.util包中的Date类,该类封装了当前的日期和时间。
Date类支持两个构造函数,如下表所示。
| 序号 | 构造函数 & 描述 |
|---|---|
| 1 | Date( ) 这个构造函数用当前日期和时间初始化对象. |
| 2 | Date(long millisec) 这个构造函数接受的参数等于自1970年1月1日午夜以来经过的毫秒数. |
以下是日期类的方法。
| 序号 | 方法 & 描述 |
|---|---|
| 1 | boolean after(Date date) 如果调用的Date对象包含日期晚于由date指定的日期,则返回true,否则返回false。 |
| 2 | boolean before(Date date) 如果调用的Date对象包含日期早于date指定的日期,则返回true,否则返回false. |
| 3 | Object clone( ) 复制日期对象. |
| 4 | int compareTo(Date date) 比较调用对象的值和日期的值。 如果值相等,则返回0。 如果调用对象早于日期,则返回负值。 如果调用对象晚于日期,则返回正值. |
| 5 | int compareTo(Object obj) 如果obj是Date类的,则与compareTo(Date)的操作相同。 否则,它会抛出一个ClassCastException. |
| 6 | boolean equals(Object date) 如果调用的Date对象包含与date指定的日期相同的时间和日期,则返回true,否则返回false. |
| 7 | long getTime( ) 返回1970年1月1日以来经过的毫秒数. |
| 8 | int hashCode( ) 返回调用对象的哈希码. |
| 9 | void setTime(long time) 按时间指定时间和日期,表示1970年1月1日午夜以来的时间(以毫秒为单位). |
| 10 | String toString( ) 将调用的Date对象转换为字符串并返回结果. |
获取当前日期和时间
这是用Java获取当前日期和时间的一种非常简单的方法。 您可以使用带有toString()方法的简单Date对象按如下方式打印当前日期和时间 -
例子
import java.util.Date;
public class DateDemo {
public static void main(String args[]) {
// Instantiate a Date object
Date date = new Date();
// display time and date using toString()
System.out.println(date.toString());
}
}
这将产生以下结果 −
on May 04 09:51:52 CDT 2009
日期比较
以下是比较两个日期的三种方法 -
- 您可以使用getTime()获取自1970年1月1日午夜以来经过的毫秒数,然后比较这两个值。
- 您可以使用before(),after()和equals()之前的方法。 例如,由于本月12日在18日之前,所以新日期(99,2,12).before(新日期(99,2,18))返回true。
- 您可以使用由Comparable接口定义并由Date实现的compareTo()方法。
使用SimpleDateFormat格式化日期
SimpleDateFormat是一个以区域敏感的方式格式化和解析日期的具体类。 SimpleDateFormat允许您首先选择用于日期时间格式的任何用户定义的模式。
例子
import java.util.*;
import java.text.*;
public class DateDemo {
public static void main(String args[]) {
Date dNow = new Date( );
SimpleDateFormat ft = new SimpleDateFormat ("E yyyy.MM.dd 'at' hh:mm:ss a zzz");
System.out.println("Current Date: " + ft.format(dNow));
}
}
这将产生以下结果 −
Current Date: Sun 2004.07.18 at 04:14:09 PM PDT
简单的DateFormat格式代码
要指定时间格式,请使用时间模式字符串。 在这种模式下,所有ASCII字母都被保留为模式字母,它们被定义为以下内容 -
| 字母 | 描述 | 例子 |
|---|---|---|
| G | 纪元标记 | AD |
| y | 四位年 | 2001 |
| M | 月 | July or 07 |
| d | 日 | 10 |
| h | A.M./P.M. (1~12)格式小时 | 12 |
| H | 一天中的小时 (0~23) | 22 |
| m | 分钟 | 30 |
| s | 秒钟 | 55 |
| S | 毫秒 | 234 |
| E | 星期 | Tuesday |
| D | 一年中日子 | 360 |
| F | 一个月中第几周的周几 | 2 (second Wed. in July) |
| w | 一年中第几周 | 40 |
| W | 一个月中第几周 | 1 |
| a | A.M./P.M. 标记 | PM |
| k | 一天中的小时(1~24) | 24 |
| K | A.M./P.M. (0~11)格式小时 | 10 |
| z | 时区 | Eastern Standard Time |
| ' | 文字定界符 | Delimiter |
| " | 单引号 | ` |
使用printf格式日期
使用printf方法可以非常容易地完成日期和时间格式化。 您使用两个字母的格式,从t开始,并以表格的一个字母结尾,如下面的代码所示。
例子
import java.util.Date;
public class DateDemo {
public static void main(String args[]) {
// Instantiate a Date object
Date date = new Date();
// display time and date
String str = String.format("Current Date/Time : %tc", date );
System.out.printf(str);
}
}
这将产生以下结果 −
Current Date/Time : Sat Dec 15 16:37:57 MST 2012
如果你需要重复提供日期,那么利用这种方式来格式化它的每一部分就有点复杂了。因此,可以利用一个格式化字符串指出要被格式化的参数的索引。
索引必须紧跟在%之后,并且必须以$结尾。
例子
import java.util.Date;
public class DateDemo {
public static void main(String args[]) {
// Instantiate a Date object
Date date = new Date();
// display time and date
System.out.printf("%1$s %2$tB %2$td, %2$tY", "Due date:", date);
}
}
这将产生以下结果 −
Due date: February 09, 2004
或者,您可以使用 < 标志。 它表示应该再次使用与前面格式规范中相同的参数。
例子
import java.util.Date;
public class DateDemo {
public static void main(String args[]) {
// Instantiate a Date object
Date date = new Date();
// display formatted date
System.out.printf("%s %tB %<te, %<tY", "Due date:", date);
}
}
这将产生以下结果 −
Due date: February 09, 2004
日期和时间转换字符
| Character | Description | Example |
|---|---|---|
| c | Complete date and time | Mon May 04 09:51:52 CDT 2009 |
| F | ISO 8601 date | 2004-02-09 |
| D | U.S. formatted date (month/day/year) | 02/09/2004 |
| T | 24-hour time | 18:05:19 |
| r | 12-hour time | 06:05:19 pm |
| R | 24-hour time, no seconds | 18:05 |
| Y | Four-digit year (with leading zeroes) | 2004 |
| y | Last two digits of the year (with leading zeroes) | 04 |
| C | First two digits of the year (with leading zeroes) | 20 |
| B | Full month name | February |
| b | Abbreviated month name | Feb |
| m | Two-digit month (with leading zeroes) | 02 |
| d | Two-digit day (with leading zeroes) | 03 |
| e | Two-digit day (without leading zeroes) | 9 |
| A | Full weekday name | Monday |
| a | Abbreviated weekday name | Mon |
| j | Three-digit day of year (with leading zeroes) | 069 |
| H | Two-digit hour (with leading zeroes), between 00 and 23 | 18 |
| k | Two-digit hour (without leading zeroes), between 0 and 23 | 18 |
| I | Two-digit hour (with leading zeroes), between 01 and 12 | 06 |
| l | Two-digit hour (without leading zeroes), between 1 and 12 | 6 |
| M | Two-digit minutes (with leading zeroes) | 05 |
| S | Two-digit seconds (with leading zeroes) | 19 |
| L | Three-digit milliseconds (with leading zeroes) | 047 |
| N | Nine-digit nanoseconds (with leading zeroes) | 047000000 |
| P | Uppercase morning or afternoon marker | PM |
| p | Lowercase morning or afternoon marker | pm |
| z | RFC 822 numeric offset from GMT | -0800 |
| Z | Time zone | PST |
| s | Seconds since 1970-01-01 00:00:00 GMT | 1078884319 |
| Q | Milliseconds since 1970-01-01 00:00:00 GMT | 1078884319047 |
还有其他有用的类与日期和时间有关。 有关更多详细信息,请参阅Java Standard文档。
将字符串解析成日期
SimpleDateFormat类有一些额外的方法,特别是parse(),它试图根据存储在指定SimpleDateFormat对象中的格式来解析字符串。
例子
import java.util.*;
import java.text.*;
public class DateDemo {
public static void main(String args[]) {
SimpleDateFormat ft = new SimpleDateFormat ("yyyy-MM-dd");
String input = args.length == 0 ? "1818-11-11" : args[0];
System.out.print(input + " Parses as ");
Date t;
try {
t = ft.parse(input);
System.out.println(t);
} catch (ParseException e) {
System.out.println("Unparseable using " + ft);
}
}
}
上述程序的示例运行会产生以下结果 −
1818-11-11 Parses as Wed Nov 11 00:00:00 EST 1818
休眠
您可以从一毫秒到计算机的整个使用期限内睡眠一段时间。 例如,下面的程序会睡3秒 −
例子
import java.util.*;
public class SleepDemo {
public static void main(String args[]) {
try {
System.out.println(new Date( ) + "\n");
Thread.sleep(5*60*10);
System.out.println(new Date( ) + "\n");
} catch (Exception e) {
System.out.println("Got an exception!");
}
}
}
这将产生以下结果 −
Sun May 03 18:04:41 GMT 2009 Sun May 03 18:04:51 GMT 2009
测量经过的时间
有时,您可能需要以毫秒为单位来测量时间点。 所以让我们再次重写上面的例子 −
例子
import java.util.*;
public class DiffDemo {
public static void main(String args[]) {
try {
long start = System.currentTimeMillis( );
System.out.println(new Date( ) + "\n");
Thread.sleep(5*60*10);
System.out.println(new Date( ) + "\n");
long end = System.currentTimeMillis( );
long diff = end - start;
System.out.println("Difference is : " + diff);
} catch (Exception e) {
System.out.println("Got an exception!");
}
}
}
这将产生以下结果 −
Sun May 03 18:16:51 GMT 2009 Sun May 03 18:16:57 GMT 2009 Difference is : 5993
GregorianCalendar类
GregorianCalendar是一个Calendar类的具体实现,它实现了您熟悉的普通格里历日历。 我们没有在本教程中讨论Calendar类,您可以为此查找标准的Java文档。
Calendar的getInstance()方法返回在默认语言环境和时区中使用当前日期和时间初始化的GregorianCalendar。 GregorianCalendar定义了两个字段:AD和BC。 这些代表了公历定义的两个时代。
正则表达式
Java 正则表达式
Java提供了用于与正则表达式进行模式匹配的java.util.regex包。 Java正则表达式与Perl编程语言非常相似,并且非常容易学习。
正则表达式是一个特殊的字符序列,可以使用模式中保存的专用语法来帮助您匹配或查找其他字符串或字符串集。它们可以用于搜索,编辑或操纵文本和数据。
java.util.regex包主要由以下三个类组成 -
- 模式类 - 模式对象是正则表达式的编译后的表示。 Pattern类不提供公共构造函数。要创建一个模式,你必须首先调用其一个public static compile()方法,然后它将返回一个Pattern对象。这些方法接受一个正则表达式作为第一个参数。
- Matcher类 - Matcher对象是解释模式并对输入字符串执行匹配操作的引擎。像Pattern类一样,Matcher没有定义公共构造函数。通过调用Pattern对象上的matcher()方法来获得Matcher对象。
- PatternSyntaxException - PatternSyntaxException对象是指示正则表达式模式中的语法错误的未经检查的异常。
捕获组
捕获组是一种将多个角色作为单个单位对待的方式。 它们是通过将字符分组在一组括号内创建的。 例如,正则表达式(dog)会创建一个包含字母“d”,“o”和“g”的组。
捕获组通过从左至右数开括号进行编号。 在表达式((A)(B(C)))中,例如,有四个这样的组 -
- ((A)(B(C)))
- (A)
- (B(C))
- (C)
要找出表达式中有多少个组,请在匹配器对象上调用groupCount方法。 groupCount方法返回一个int,显示匹配器模式中存在的捕获组的数量。
还有一个特殊的组,0组,它总是代表整个表达。 该组不包括在由groupCount报告的总数中。
以下示例说明如何从给定的字母数字字符串中查找数字字符串 -
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class RegexMatches {
public static void main( String args[] ) {
// String to be scanned to find the pattern.
String line = "This order was placed for QT3000! OK?";
String pattern = "(.*)(\\d+)(.*)";
// Create a Pattern object
Pattern r = Pattern.compile(pattern);
// Now create matcher object.
Matcher m = r.matcher(line);
if (m.find( )) {
System.out.println("Found value: " + m.group(0) );
System.out.println("Found value: " + m.group(1) );
System.out.println("Found value: " + m.group(2) );
}else {
System.out.println("NO MATCH");
}
}
}
这将产生以下结果&minus;
Found value: This order was placed for QT3000! OK? Found value: This order was placed for QT300 Found value: 0
正则表达式语法
下表列出了Java中可用的所有正则表达式元字符语法 -
| 子表达式 | 匹配 |
|---|---|
| ^ | 匹配输入字符串开始的位置。 |
| $ | 匹配输入字符串结尾的位置。 |
| . | 匹配除换行符之外的任何单个字符。 使用m选项也可以匹配换行符。 |
| [...] | 与括号中的任何单个字符匹配。 |
| [^...] | 匹配括号内的任何单个字符。 |
| \A | 整个字符串的开头。 |
| \z | 整个字符串的结尾。 |
| \Z | 除允许的最终行结束符外,整个字符串的结尾。 |
| re* | 与前面的表达式匹配0次或更多次。 |
| re+ | 匹配以前的一个或多个东西。 |
| re? | 与前面的表达式匹配0或1次。 |
| re{ n} | 恰好匹配n个前面表达式的出现次数。 |
| re{ n,} | 与前面的表达式匹配n次或更多次。 |
| re{ n, m} | 匹配前面表达式的至少n次和最多m次。 |
| a| b | 匹配a或b。 |
| (re) | 对正则表达式进行分组并记住匹配的文本。 |
| (?: re) | 对正则表达式进行分组而不记住匹配的文本。 |
| (?> re) | 无回溯匹配独立模式。 |
| \w | 匹配单词字符。 |
| \W | 匹配非字字符。 |
| \s | 匹配空格。 相当于[\ t \ n \ r \ f]。 |
| \S | 匹配非空白。 |
| \d | 匹配数字。 相当于[0-9]。 |
| \D | 匹配非数字。 |
| \A | 匹配字符串的开头。 |
| \Z | 匹配字符串的结尾。 如果存在换行符,它就在换行符之前匹配。 |
| \z | 匹配字符串的结尾。 |
| \G | 匹配点在最后一次匹配完成的位置。 |
| \n | 反向引用捕获组号“n”。 |
| \b | 在括号外匹配单词边界。 在括号内匹配退格(0x08)。 |
| \B | 匹配非字边界。 |
| \n, \t, etc. | 匹配换行符,回车符,制表符等 |
| \Q | 转义(引用)所有字符,直至\ E。 |
Matcher 类的方法
索引方法
索引方法提供了有用的索引值,精确表明输入字符串中在哪能找到匹配 -
| 序号 | 方法 & 描述 |
|---|---|
| 1 | public int start() 返回以前匹配的初始索引。 |
| 2 | public int start(int group) 返回在以前的匹配操作期间,由给定组所捕获的子序列的初始索引 |
| 3 | public int end() 返回最后匹配字符之后的偏移量。 |
| 4 | public int end(int group) 返回在以前的匹配操作期间,由给定组所捕获子序列的最后字符之后的偏移量。 |
研究方法
研究方法用来检查输入字符串并返回一个布尔值,表示是否找到该模式
| 序号 | 方法 & 描述 |
|---|---|
| 1 | public boolean lookingAt() 尝试将从区域开头开始的输入序列与该模式匹配。 |
| 2 | public boolean find() 尝试查找与该模式匹配的输入序列的下一个子序列。 |
| 3 | public boolean find(int start) 重置此匹配器,然后尝试查找匹配该模式、从指定索引开始的输入序列的下一个子序列。 |
| 4 | public boolean matches() 尝试将整个区域与模式匹配。 |
替换方法
替换方法是替换输入字符串里文本的方法
| 序号 | 方法 & 描述 |
|---|---|
| 1 | public Matcher appendReplacement(StringBuffer sb, String replacement) 实现非终端添加和替换步骤。 |
| 2 | public StringBuffer appendTail(StringBuffer sb) 实现终端添加和替换步骤。 |
| 3 | public String replaceAll(String replacement) 替换模式与给定替换字符串相匹配的输入序列的每个子序列。 |
| 4 | public String replaceFirst(String replacement) 替换模式与给定替换字符串匹配的输入序列的第一个子序列。 |
| 5 | public static String quoteReplacement(String s) 返回指定字符串的字面替换字符串。这个方法返回一个字符串,就像传递给Matcher类的appendReplacement 方法一个字面字符串一样工作。 |
start和end 方法
以下是计算单词“cat”出现在输入字符串中的次数的示例 -
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class RegexMatches {
private static final String REGEX = "\\bcat\\b";
private static final String INPUT = "cat cat cat cattie cat";
public static void main( String args[] ) {
Pattern p = Pattern.compile(REGEX);
Matcher m = p.matcher(INPUT); // get a matcher object
int count = 0;
while(m.find()) {
count++;
System.out.println("Match number "+count);
System.out.println("start(): "+m.start());
System.out.println("end(): "+m.end());
}
}
}
这将产生以下结果 -
Match number 1 start(): 0 end(): 3 Match number 2 start(): 4 end(): 7 Match number 3 start(): 8 end(): 11 Match number 4 start(): 19 end(): 22
你可以看到这个例子使用单词边界来确保字母“c”“a”“t”不仅仅是一个较长单词中的子字符串。 它还提供了一些关于匹配发生在输入字符串中的有用信息。
start方法返回上一次匹配操作期间给定组捕获的子序列的开始索引,结束时返回匹配的最后一个字符的索引加1。
matches和lookingAt 方法
matches和lookAt方法都尝试将输入序列与模式匹配。 但是,不同之处在于matches需要整个输入序列匹配,而lookAt不匹配。
两种方法始终始于输入字符串的开头。 这里是解释功能的例子 -
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class RegexMatches {
private static final String REGEX = "foo";
private static final String INPUT = "fooooooooooooooooo";
private static Pattern pattern;
private static Matcher matcher;
public static void main( String args[] ) {
pattern = Pattern.compile(REGEX);
matcher = pattern.matcher(INPUT);
System.out.println("Current REGEX is: "+REGEX);
System.out.println("Current INPUT is: "+INPUT);
System.out.println("lookingAt(): "+matcher.lookingAt());
System.out.println("matches(): "+matcher.matches());
}
}
这将产生以下结果 -
Current REGEX is: foo Current INPUT is: fooooooooooooooooo lookingAt(): true matches(): false
replaceFirst和replaceAll 方法
replaceFirst和replaceAll方法替换与给定正则表达式匹配的文本。 正如它们的名称所示,replaceFirst替换第一个匹配项,replaceAll替换所有匹配项。
这里是解释功能的例子 -
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class RegexMatches {
private static String REGEX = "dog";
private static String INPUT = "The dog says meow. " + "All dogs say meow.";
private static String REPLACE = "cat";
public static void main(String[] args) {
Pattern p = Pattern.compile(REGEX);
// get a matcher object
Matcher m = p.matcher(INPUT);
INPUT = m.replaceAll(REPLACE);
System.out.println(INPUT);
}
}
这将产生以下结果 -
The cat says meow. All cats say meow.
appendReplacement和appendTail 方法
Matcher类还为文本替换提供了appendReplacement和appendTail方法。
这里是解释功能的例子 -
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class RegexMatches {
private static String REGEX = "a*b";
private static String INPUT = "aabfooaabfooabfoob";
private static String REPLACE = "-";
public static void main(String[] args) {
Pattern p = Pattern.compile(REGEX);
// get a matcher object
Matcher m = p.matcher(INPUT);
StringBuffer sb = new StringBuffer();
while(m.find()) {
m.appendReplacement(sb, REPLACE);
}
m.appendTail(sb);
System.out.println(sb.toString());
}
}
这将产生以下结果 -
-foo-foo-foo-
PatternSyntaxException 类的方法
PatternSyntaxException 是一个非强制异常类,它指示一个正则表达式模式中的语法错误。
PatternSyntaxException 类提供了下面的方法来帮助我们查看发生了什么错误。
| 序号 | 方法 & 描述 |
|---|---|
| 1 | public String getDescription() 获取错误的描述。 |
| 2 | public int getIndex() 获取错误的索引。 |
| 3 | public String getPattern() 获取错误的正则表达式模式。 |
| 4 | public String getMessage() 返回多行字符串,包含语法错误及其索引的描述、错误的正则表达式模式和模式中错误索引的可视化指示。 |
方法
Java 方法
Java方法是组合在一起以执行操作的语句的集合。 例如,当您调用System.out.println()方法时,系统实际上会执行几个语句以在控制台上显示消息。
现在您将学习如何创建具有或不具有返回值的自己的方法,调用带或不带参数的方法,并在程序设计中应用方法抽象。
创建方法
考虑下面的例子来解释一种方法的语法 -
语法
public static int methodName(int a, int b) {
// body
}
- public static - 修饰符
- int - 返回类型
- methodName - 方法的名称
- a,b - 形式参数
- int a,int b - 参数列表
方法定义由一个方法头和一个方法体组成。 以下语法显示了相同的内容 -
语法
modifier returnType nameOfMethod (Parameter List) {
// method body
}
上面显示的语法包括 -
- modifier - 它定义了方法的访问类型,它是可选的使用。
- returnType - 方法可能会返回一个值。
- nameOfMethod - 这是方法名称。 方法签名由方法名称和参数列表组成。
- Parameter List - 参数列表,它是方法的类型,顺序和参数数量。 这些是可选的,方法可能包含零参数。
- method body - 方法体定义了方法对这些语句的作用。
例子
这是上面定义的方法min()的源代码。 该方法使用两个参数num1和num2,并返回两者之间的最大值 -
/** the snippet returns the minimum between two numbers */
public static int minFunction(int n1, int n2) {
int min;
if (n1 > n2)
min = n2;
else
min = n1;
return min;
}
方法调用
对于使用方法,应该调用它。 有两种调用方法的方法,即方法返回一个值或不返回任何值(不返回值)。
方法调用的过程很简单。 当一个程序调用一个方法时,程序控制转移到被调用的方法。 这个被调用的方法然后在两种情况下将控制返回给调用者,
- return语句被执行。
- 它达到了结束大括号的方法。
返回void的方法被认为是调用语句。 让我们考虑一个例子 -
System.out.println("This is tutorialspoint.com!");
返回值的方法可以通过以下示例来理解 -
int result = sum(6, 9);
以下是演示如何定义方法以及如何调用方法的示例 -
例子
public class ExampleMinNumber {
public static void main(String[] args) {
int a = 11;
int b = 6;
int c = minFunction(a, b);
System.out.println("Minimum Value = " + c);
}
/** returns the minimum of two numbers */
public static int minFunction(int n1, int n2) {
int min;
if (n1 > n2)
min = n2;
else
min = n1;
return min;
}
}
这将产生下面结果 −
Minimum value = 6
void 关键词
void关键字允许我们创建不返回值的方法。 在下面的例子中,我们正在考虑一个无效方法methodRankPoints。 此方法是一个无效方法,它不返回任何值。 调用void方法必须是一个语句,即methodRankPoints(255.7);. 它是一个Java语句,以分号结尾,如以下示例所示。
例子
public class ExampleVoid {
public static void main(String[] args) {
methodRankPoints(255.7);
}
public static void methodRankPoints(double points) {
if (points >= 202.5) {
System.out.println("Rank:A1");
}else if (points >= 122.4) {
System.out.println("Rank:A2");
}else {
System.out.println("Rank:A3");
}
}
}
这将产生下面结果 −
Rank:A1
按值传递参数
在调用过程中工作时,参数将被传递。 这些应该与方法规范中它们各自的参数的顺序相同。 参数可以通过值或引用传递。
按值传递参数意味着使用参数调用方法。 通过这个,参数值被传递给参数。
以下程序显示了按值传递参数的示例。 即使在方法调用之后,参数的值也保持不变。
public class swappingExample {
public static void main(String[] args) {
int a = 30;
int b = 45;
System.out.println("Before swapping, a = " + a + " and b = " + b);
// Invoke the swap method
swapFunction(a, b);
System.out.println("\n**Now, Before and After swapping values will be same here**:");
System.out.println("After swapping, a = " + a + " and b is " + b);
}
public static void swapFunction(int a, int b) {
System.out.println("Before swapping(Inside), a = " + a + " b = " + b);
// Swap n1 with n2
int c = a;
a = b;
b = c;
System.out.println("After swapping(Inside), a = " + a + " b = " + b);
}
}
这将产生以下结果 −
Before swapping, a = 30 and b = 45 Before swapping(Inside), a = 30 b = 45 After swapping(Inside), a = 45 b = 30 **Now, Before and After swapping values will be same here**: After swapping, a = 30 and b is 45
方法重载
当一个类有两个或多个相同名称但参数不同的方法时,它被称为方法重载。 这与重写不同。 在重写时,一个方法具有相同的方法名称,类型,参数数量等。
让我们考虑前面讨论的例子来寻找最小数量的整数类型。 如果,我们假设我们想要找到最小数量的double类型。 然后引入重载的概念来创建两个或多个具有相同名称但参数不同的方法。
下面的例子解释了相同的 -
例子
public class ExampleOverloading {
public static void main(String[] args) {
int a = 11;
int b = 6;
double c = 7.3;
double d = 9.4;
int result1 = minFunction(a, b);
// same function name with different parameters
double result2 = minFunction(c, d);
System.out.println("Minimum Value = " + result1);
System.out.println("Minimum Value = " + result2);
}
// for integer
public static int minFunction(int n1, int n2) {
int min;
if (n1 > n2)
min = n2;
else
min = n1;
return min;
}
// for double
public static double minFunction(double n1, double n2) {
double min;
if (n1 > n2)
min = n2;
else
min = n1;
return min;
}
}
这将产生以下结果 −
Minimum Value = 6 Minimum Value = 7.3
重载方法使程序可读。 在这里,两个方法是由相同的名称给出,但具有不同的参数。 结果是整数和双精度型的最小数。
使用命令行参数
有时候,当你运行它时,你会想把一些信息传递给一个程序。 这是通过将命令行参数传递给main()来完成的。
命令行参数是在执行命令行时直接跟随程序名称的信息。 访问Java程序中的命令行参数非常简单。 它们作为字符串存储在传递给main()的String数组中。
以下程序将显示所有用它调用的命令行参数 -
public class CommandLine {
public static void main(String args[]) {
for(int i = 0; i<args.length; i++) {
System.out.println("args[" + i + "]: " + args[i]);
}
}
}
尝试执行此程序,如下所示 -
$java CommandLine this is a command line 200 -100
这将产生以下结果 -
args[0]: this args[1]: is args[2]: a args[3]: command args[4]: line args[5]: 200 args[6]: -100
构造函数
构造函数在创建时初始化一个对象。 它与它的类具有相同的名称,并且在语法上类似于一种方法。 但是,构造函数没有显式的返回类型。
通常,您将使用构造函数为由该类定义的实例变量提供初始值,或者执行创建完全形成的对象所需的任何其他启动过程。
所有类都有构造函数,不管你是否定义了一个构造函数,因为Java会自动提供一个默认构造函数,将所有成员变量初始化为零。 但是,一旦你定义了你自己的构造函数,就不再使用默认的构造函数。
这是一个简单的例子,它使用了一个不带参数的构造函数 -
// A simple constructor.
class MyClass {
int x;
// Following is the constructor
MyClass() {
x = 10;
}
}
你将不得不调用构造函数来初始化对象,如下所示 −
public class ConsDemo {
public static void main(String args[]) {
MyClass t1 = new MyClass();
MyClass t2 = new MyClass();
System.out.println(t1.x + " " + t2.x);
}
}
10 10
参数化的构造函数
大多数情况下,您将需要一个接受一个或多个参数的构造函数。 参数以与添加到方法相同的方式添加到构造函数中,只需在构造函数名称后的括号内声明它们即可。
下面是一个简单的例子,它使用带参数的构造函数 -
// A simple constructor.
class MyClass {
int x;
// Following is the constructor
MyClass(int i ) {
x = i;
}
}
你将需要调用一个构造函数来初始化对象,如下所示 −
public class ConsDemo {
public static void main(String args[]) {
MyClass t1 = new MyClass( 10 );
MyClass t2 = new MyClass( 20 );
System.out.println(t1.x + " " + t2.x);
}
}
这将产生以下结果 −
10 20
this 关键字
this是Java中的一个关键字,用作对当前类的对象的引用,在实例方法或构造函数中使用。 使用这个你可以引用一个类的成员,比如构造函数,变量和方法。
注 - 关键字this仅用于实例方法或构造函数中...
一般来说,这个关键字用于 -
- 在构造函数或方法内区分实例变量和局部变量(如果它们具有相同的名称)。
class Student {
int age;
Student(int age) {
this.age = age;
}
}
- 在类中调用其他类型的构造函数(参数化构造函数或默认值)。 它被称为显式构造函数调用。
class Student {
int age
Student() {
this(20);
}
Student(int age) {
this.age = age;
}
}
以下是使用此关键字访问类成员的示例。 将以下程序复制并粘贴到名为This_Example.java的文件中。
public class This_Example {
// Instance variable num
int num = 10;
This_Example() {
System.out.println("This is an example program on keyword this");
}
This_Example(int num) {
// Invoking the default constructor
this();
// Assigning the local variable num to the instance variable num
this.num = num;
}
public void greet() {
System.out.println("Hi Welcome to Tutorialspoint");
}
public void print() {
// Local variable num
int num = 20;
// Printing the local variable
System.out.println("value of local variable num is : "+num);
// Printing the instance variable
System.out.println("value of instance variable num is : "+this.num);
// Invoking the greet method of a class
this.greet();
}
public static void main(String[] args) {
// Instantiating the class
This_Example obj1 = new This_Example();
// Invoking the print method
obj1.print();
// Passing a new value to the num variable through parametrized constructor
This_Example obj2 = new This_Example(30);
// Invoking the print method again
obj2.print();
}
}
这将产生以下结果 −
This is an example program on keyword this value of local variable num is : 20 value of instance variable num is : 10 Hi Welcome to Tutorialspoint This is an example program on keyword this value of local variable num is : 20 value of instance variable num is : 30 Hi Welcome to Tutorialspoint
可变参数(var-args)
JDK 1.5使您可以将相同类型的可变数量的参数传递给方法。 该方法中的参数声明如下 -
typeName... parameterName
在方法声明中,指定类型后跟省略号(...)。 一个方法中只能指定一个变长参数,并且该参数必须是最后一个参数。 任何常规参数必须在它之前。
例子
public class VarargsDemo {
public static void main(String args[]) {
// Call method with variable args
printMax(34, 3, 3, 2, 56.5);
printMax(new double[]{1, 2, 3});
}
public static void printMax( double... numbers) {
if (numbers.length == 0) {
System.out.println("No argument passed");
return;
}
double result = numbers[0];
for (int i = 1; i < numbers.length; i++)
if (numbers[i] > result)
result = numbers[i];
System.out.println("The max value is " + result);
}
}
这将产生以下结果 -
The max value is 56.5 The max value is 3.0
finalize( ) 方法
可以定义一个方法,该方法在垃圾收集器最后一个对象被销毁之前被调用。 这个方法叫做finalize(),它可以用来确保一个对象干净地终止。
例如,您可以使用finalize()来确保该对象拥有的打开文件已关闭。
要为类添加终结器,只需定义finalize()方法即可。 Java运行时在它要回收该类的对象时调用该方法。
在finalize()方法内部,您将指定在对象销毁之前必须执行的那些操作。
finalize()方法具有这种一般形式 -
protected void finalize( ) {
// finalization code here
}
这里,关键字protected是一个说明符,它可以防止通过在其类的外部定义的代码来访问finalize()。
这意味着你无法知道何时甚至是否会执行finalize()。 例如,如果程序在垃圾回收发生之前结束,那么finalize()将不会执行。
文件和输入输出
Java 文件和输入输出
java.io包几乎包含您可能需要用Java执行输入和输出(I / O)所需的每个类。 所有这些流代表输入源和输出目标。 java.io包中的流支持许多数据,如基元,对象,本地化字符等。
输入输出流
一个流可以被定义为一个数据序列。 有两种流 -
- InPutStream - InputStream用于从源读取数据。
- OutPutStream - OutputStream用于将数据写入目标。
字节流
Java字节流用于执行8位字节的输入和输出。 尽管有许多与字节流相关的类,但最常用的类是FileInputStream和FileOutputStream。 以下是使用这两个类将输入文件复制到输出文件的示例 -
例子
import java.io.*;
public class CopyFile {
public static void main(String args[]) throws IOException {
FileInputStream in = null;
FileOutputStream out = null;
try {
in = new FileInputStream("input.txt");
out = new FileOutputStream("output.txt");
int c;
while ((c = in.read()) != -1) {
out.write(c);
}
}finally {
if (in != null) {
in.close();
}
if (out != null) {
out.close();
}
}
}
}
现在让我们有一个带有以下内容的文件input.txt -
This is test for copy file.
下一步,编译上述程序并执行它,这将导致创建output.txt文件,其文件与input.txt中的内容相同。 所以让我们把上面的代码放在CopyFile.java文件中,然后执行以下操作 -
$javac CopyFile.java $java CopyFile
字符流
Java字节流用于执行8位字节的输入和输出,而Java字符流用于执行16位unicode的输入和输出。 虽然有很多与字符流相关的类,但最常用的类是FileReader和FileWriter。 尽管内部FileReader使用FileInputStream,FileWriter使用FileOutputStream,但这里主要区别在于FileReader一次读取两个字节,FileWriter一次写入两个字节。
我们可以重写上面的例子,它使用这两个类将输入文件(具有unicode字符)复制到输出文件中 -
例子
import java.io.*;
public class CopyFile {
public static void main(String args[]) throws IOException {
FileReader in = null;
FileWriter out = null;
try {
in = new FileReader("input.txt");
out = new FileWriter("output.txt");
int c;
while ((c = in.read()) != -1) {
out.write(c);
}
}finally {
if (in != null) {
in.close();
}
if (out != null) {
out.close();
}
}
}
}
现在让我们有一个带有以下内容的文件input.txt -
This is test for copy file.
下一步,编译上述程序并执行它,这将导致创建output.txt文件,其文件与input.txt中的内容相同。 所以让我们把上面的代码放在CopyFile.java文件中,然后执行以下操作 -
$javac CopyFile.java $java CopyFile
标准输入输出流
所有的编程语言都提供对标准I / O的支持,用户的程序可以从键盘获取输入,然后在计算机屏幕上生成输出。如果您了解C或C ++编程语言,则必须了解三种标准设备STDIN,STDOUT和STDERR。同样,Java提供以下三种标准流 -
- 标准输入 - 用于向用户程序提供数据,通常键盘用作标准输入流,表示为System.in。
- 标准输出 - 用于输出用户程序产生的数据,通常计算机屏幕用于标准输出流,表示为System.out。
- 标准错误 - 用于输出用户程序产生的错误数据,通常计算机屏幕用于标准错误流并表示为System.err。
以下是一个简单的程序,该程序创建InputStreamReader以读取标准输入流,直到用户输入“q” -
例子
import java.io.*;
public class ReadConsole {
public static void main(String args[]) throws IOException {
InputStreamReader cin = null;
try {
cin = new InputStreamReader(System.in);
System.out.println("Enter characters, 'q' to quit.");
char c;
do {
c = (char) cin.read();
System.out.print(c);
} while(c != 'q');
}finally {
if (cin != null) {
cin.close();
}
}
}
}
让我们将上面的代码保存在ReadConsole.java文件中,并尝试编译并执行它,如下面的程序所示。 这个程序继续读取并输出相同的字符,直到我们按'q' -
$javac ReadConsole.java $java ReadConsole Enter characters, 'q' to quit. 1 1 e e q q
读写文件
如前所述,一个流可以被定义为一个数据序列。 InputStream用于从源读取数据,OutputStream用于将数据写入目标。
这是处理输入和输出流的类的层次结构。
两个重要的流是FileInputStream和FileOutputStream,这将在本教程中讨论。
FileInputStream
该流用于从文件中读取数据。 可以使用关键字new创建对象,并且可以使用几种类型的构造函数。
以下构造函数将文件名作为字符串创建输入流对象来读取文件 -
InputStream f = new FileInputStream("C:/java/hello");
以下构造函数需要一个文件对象来创建一个输入流对象来读取文件。 首先我们使用File()方法创建一个文件对象,如下所示 -
File f = new File("C:/java/hello");
InputStream f = new FileInputStream(f);
一旦你有了InputStream对象,那么就有一个辅助方法列表,它可以用来读取流或者在流上进行其他操作。
| 序号 | 方法 & 描述 |
|---|---|
| 1 | public void close() throws IOException{} 关闭此文件输入流并释放与此流有关的所有系统资源。抛出IOException异常。 |
| 2 | protected void finalize()throws IOException {} 这个方法清除与该文件的连接。确保在不再引用文件输入流时调用其 close 方法。抛出IOException异常。 |
| 3 | public int read(int r)throws IOException{} 这个方法从 InputStream 对象读取指定字节的数据。返回为整数值。返回下一字节数据,如果已经到结尾则返回-1。 |
| 4 | public int read(byte[] r) throws IOException{} 这个方法从输入流读取r.length长度的字节。返回读取的字节数。如果是文件结尾则返回-1。 |
| 5 | public int available() throws IOException{} 返回下一次对此输入流调用的方法可以不受阻塞地从此输入流读取的字节数。返回一个整数值。 |
除了 InputStream 外,还有一些其他的输入流ByteArrayInputStream,DataInputStream。
FileOutputStream
FileOutputStream用于创建文件并向其中写入数据。 在打开输出之前,流将创建一个文件(如果它尚不存在的话)。
这里有两个可用于创建FileOutputStream对象的构造函数。
以下构造函数将文件名作为字符串创建输入流对象以写入文件 -
OutputStream f = new FileOutputStream("C:/java/hello")
以下构造函数需要一个文件对象来创建一个输出流对象来写入文件。 首先,我们使用File()方法创建一个文件对象,如下所示 -
File f = new File("C:/java/hello");
OutputStream f = new FileOutputStream(f);
一旦你有了OutputStream对象,那么就有一个帮助器方法列表,可以用来写入流或在流上执行其他操作。
| 序号 | 方法 & 描述 |
|---|---|
| 1 | public void close() throws IOException{} 关闭此文件输入流并释放与此流有关的所有系统资源。抛出IOException异常。 |
| 2 | protected void finalize()throws IOException {} 这个方法清除与该文件的连接。确保在不再引用文件输入流时调用其 close 方法。抛出IOException异常。 |
| 3 | public void write(int w)throws IOException{} 这个方法把指定的字节写到输出流中。 |
| 4 | public void write(byte[] w) 把指定数组中w.length长度的字节写到OutputStream中。 |
除了OutputStream外,还有一些其他的输出流ByteArrayInputStream,DataInputStream。
例子
以下是演示InputStream和OutputStream的示例 -
import java.io.*;
public class fileStreamTest {
public static void main(String args[]) {
try {
byte bWrite [] = {11,21,3,40,5};
OutputStream os = new FileOutputStream("test.txt");
for(int x = 0; x < bWrite.length ; x++) {
os.write( bWrite[x] ); // writes the bytes
}
os.close();
InputStream is = new FileInputStream("test.txt");
int size = is.available();
for(int i = 0; i < size; i++) {
System.out.print((char)is.read() + " ");
}
is.close();
} catch (IOException e) {
System.out.print("Exception");
}
}
}
上面的代码会创建文件test.txt并以二进制格式写入给定的数字。 标准输出屏幕上的输出也是一样。
Java中的目录
目录是一个可以包含其他文件和目录列表的文件。 您使用File对象创建目录,以列出目录中可用的文件。 有关完整的详细信息,请查看您可以在File对象上调用的所有方法的列表以及与目录相关的内容。
创建目录
有两个有用的文件实用程序方法,可用于创建目录 -
- mkdir()方法创建一个目录,成功时返回true,失败时返回false。 失败表示File对象中指定的路径已经存在,或者由于整个路径尚不存在而无法创建目录。
- mkdirs()方法创建目录和目录的所有父项。
以下示例创建“/ tmp / user / java / bin”目录 -
例子
import java.io.File;
public class CreateDir {
public static void main(String args[]) {
String dirname = "/tmp/user/java/bin";
File d = new File(dirname);
// Create directory now.
d.mkdirs();
}
}
编译并执行上面的代码来创建“/ tmp / user / java / bin”。
注 - Java按照惯例自动处理UNIX和Windows上的路径分隔符。 如果在Windows版本的Java上使用正斜杠(/),则该路径仍然可以正确解析。
列举目录
您可以使用File对象提供的list()方法列出目录中可用的所有文件和目录,如下所示 -
例子
import java.io.File;
public class ReadDir {
public static void main(String[] args) {
File file = null;
String[] paths;
try {
// create new file object
file = new File("/tmp");
// array of files and directory
paths = file.list();
// for each name in the path array
for(String path:paths) {
// prints filename and directory name
System.out.println(path);
}
} catch (Exception e) {
// if any error occurs
e.printStackTrace();
}
}
}
这将基于/ tmp目录中的目录和文件生成以下结果 -
test1.txt test2.txt ReadDir.java ReadDir.class
异常处理
Java 异常处理
异常(或异常事件)是执行程序期间出现的问题。 当出现异常时,程序的正常流程中断,程序/应用程序异常终止,这是不推荐的,因此需要处理这些异常。
由于许多不同的原因可能会发生异常。 以下是发生异常的一些情况。
- 用户输入了无效的数据。
- 无法找到需要打开的文件。
- 在通信过程中网络连接丢失或JVM内存不足。
其中一些异常情况是由用户错误引起的,其他情况是由程序员错误造成的,另一些异常情况是由于某种方式失败的物理资源造成的。
基于这些,我们有三类例外。 您需要了解它们以了解异常处理在Java中的工作原理。
- 检查性异常最具代表的检查性异常是用户错误或问题引起的异常,这是程序员无法预见的。例如要打开一个不存在文件时,一个异常就发生了,这些异常在编译时不能被简单地忽略。
例如,如果在程序中使用FileReader类从文件读取数据,如果其构造函数中指定的文件不存在,则会发生FileNotFoundException,编译器会提示程序员处理该异常。
例子
import java.io.File;
import java.io.FileReader;
public class FilenotFound_Demo {
public static void main(String args[]) {
File file = new File("E://file.txt");
FileReader fr = new FileReader(file);
}
}
如果您尝试编译上述程序,您将得到以下例外.
C:\>javac FilenotFound_Demo.java FilenotFound_Demo.java:8: error: unreported exception FileNotFoundException; must be caught or declared to be thrown FileReader fr = new FileReader(file); ^ 1 error
注 - 由于FileReader类的read()和close()方法会引发IOException,因此您可以观察到编译器会通知处理IOException以及FileNotFoundException。
- 未经检查的异常 - 未经检查的异常是执行时发生的异常。 这些也被称为运行时例外。 这些包括编程错误,例如逻辑错误或不当使用API。 运行时异常在编译时被忽略。
例如,如果您在程序中声明了大小为5的数组,并尝试调用数组的第6个元素,则会发生ArrayIndexOutOfBoundsExceptionexception。
例子
public class Unchecked_Demo {
public static void main(String args[]) {
int num[] = {1, 2, 3, 4};
System.out.println(num[5]);
}
}
如果您尝试编译上述程序,您将得到以下例外.
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 5 at Exceptions.Unchecked_Demo.main(Unchecked_Demo.java:8)
- 错误 - 这些都不是异常,但是在用户或程序员的控制之外出现的问题。 在您的代码中通常会忽略错误,因为您很少可以对错误进行任何操作。 例如,如果发生堆栈溢出,则会出现错误。 在编译时它们也被忽略。
Exception 类的层次
所有异常类都是java.lang.Exception类的子类型。 异常类是Throwable类的一个子类。 除了异常类以外,还有另一个名为Error的子类,它是从Throwable类派生的。
错误是在发生严重故障时发生的异常情况,这些情况不由Java程序处理。 生成错误以指示运行时环境生成的错误。 示例:JVM内存不足。 通常,程序无法从错误中恢复。
Exception类有两个主要的子类:IOException类和RuntimeException类。
Exceptions 方法
以下是Throwable类中可用的重要方法的列表。
| 序号 | 方法 & 描述 |
|---|---|
| 1 | public String getMessage() 返回关于发生的异常的详细信息。这个消息在Throwable 类的构造函数中初始化了。 |
| 2 | public Throwable getCause() 返回一个Throwable 对象代表异常原因。 |
| 3 | public String toString() 使用getMessage()的结果返回类的串级名字。 |
| 4 | public void printStackTrace() 打印toString()结果和栈层次到System.err,即错误输出流。 |
| 5 | public StackTraceElement [] getStackTrace() 返回一个包含堆栈层次的数组。下标为0的元素代表栈顶,最后一个元素代表方法调用堆栈的栈底。 |
| 6 | public Throwable fillInStackTrace() 用当前的调用栈层次填充Throwable 对象栈层次,添加到栈层次任何先前信息中。 |
捕捉异常
一个方法使用try和catch关键字的组合捕获异常。 try / catch块放置在可能产生异常的代码周围。 try / catch块内的代码被称为受保护代码,使用try / catch的语法如下所示 -
语法
try {
// Protected code
} catch (ExceptionName e1) {
// Catch block
}
易出现异常的代码放置在try块中。 发生异常时,发生的异常由与其关联的catch块处理。 每个try块应该紧跟在catch块或finally块之后。
catch语句涉及到声明你试图捕获的异常的类型。 如果在受保护的代码中发生异常,则检查try后面的catch块(或块)。 如果在catch块中列出发生的异常类型,则将异常传递给catch块,这是因为将参数传递给方法参数。
以下是使用2个元素声明的数组。 然后代码尝试访问引发异常的数组的第三个元素。
// File Name : ExcepTest.java
import java.io.*;
public class ExcepTest {
public static void main(String args[]) {
try {
int a[] = new int[2];
System.out.println("Access element three :" + a[3]);
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("Exception thrown :" + e);
}
System.out.println("Out of the block");
}
}
这将产生以下结果 −
Exception thrown :java.lang.ArrayIndexOutOfBoundsException: 3 Out of the block
多个捕获块
一个try块可以跟着多个catch块。 多个catch块的语法如下所示 -
语法
try {
// Protected code
} catch (ExceptionType1 e1) {
// Catch block
} catch (ExceptionType2 e2) {
// Catch block
} catch (ExceptionType3 e3) {
// Catch block
}
前面的陈述展示了三个catch块,但是你可以在一次尝试之后得到任意数量的块。 如果受保护的代码中发生异常,则会将该异常引发到列表中的第一个catch块。 如果引发的异常的数据类型匹配ExceptionType1,它会在那里被捕获。 如果不是,则异常传递到第二个catch语句。 这种情况一直持续到异常被捕获或落入所有捕获,在这种情况下,当前方法停止执行,并且异常被抛出到调用堆栈上的前一个方法。
这里是显示如何使用多个try / catch语句的代码段。
try {
file = new FileInputStream(fileName);
x = (byte) file.read();
} catch (IOException i) {
i.printStackTrace();
return -1;
} catch (FileNotFoundException f) // Not valid! {
f.printStackTrace();
return -1;
}
捕捉多种类型的例外
自Java 7以来,您可以使用单个catch块处理多个异常,此功能简化了代码。 这里是你如何做到这一点 -
catch (IOException|FileNotFoundException ex) {
logger.log(ex);
throw ex;
}
Throws/Throw 关键词
如果方法不处理检查的异常,则该方法必须使用throws关键字来声明它。 throws关键字出现在方法签名的末尾。
通过使用throw关键字,可以抛出一个异常,或者是一个新实例化的异常,或者是您刚捕获的异常。
尝试理解throws和throw关键字之间的区别,throws用于推迟检查异常的处理,throw用于显式调用异常。
下面的方法声明它抛出一个RemoteException -
例子
import java.io.*;
public class className {
public void deposit(double amount) throws RemoteException {
// Method implementation
throw new RemoteException();
}
// Remainder of class definition
}
一个方法可以声明它抛出了多个异常,在这种情况下,异常在由逗号分隔的列表中声明。 例如,下面的方法声明它会抛出一个RemoteException和一个InsufficientFundsException -
例子
import java.io.*;
public class className {
public void withdraw(double amount) throws RemoteException,
InsufficientFundsException {
// Method implementation
}
// Remainder of class definition
}
Finally 关键词
finally块遵循try块或catch块。 无论是否出现异常,总是会执行代码块。
使用finally块允许您运行任何要执行的清理类型的语句,而不管受保护的代码中发生了什么。
finally块出现在catch块的末尾,并具有以下语法 -
语法
try {
// Protected code
} catch (ExceptionType1 e1) {
// Catch block
} catch (ExceptionType2 e2) {
// Catch block
} catch (ExceptionType3 e3) {
// Catch block
}finally {
// The finally block always executes.
}
例子
public class ExcepTest {
public static void main(String args[]) {
int a[] = new int[2];
try {
System.out.println("Access element three :" + a[3]);
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("Exception thrown :" + e);
}finally {
a[0] = 6;
System.out.println("First element value: " + a[0]);
System.out.println("The finally statement is executed");
}
}
}
这将产生以下结果 −
Exception thrown :java.lang.ArrayIndexOutOfBoundsException: 3 First element value: 6 The finally statement is executed
请注意以下事项 -
- 没有try语句的catch子句不能存在。
- 当try / catch块存在时,最后不需要强制子句。
- 没有catch子句或finally子句,try块不能出现。
- 任何代码不能出现在try,catch,finally块之间。
try-with-resources
通常,当我们使用流,连接等任何资源时,我们必须使用finally块明确关闭它们。 在下面的程序中,我们使用FileReader从文件中读取数据,并使用finally块关闭它。
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
public class ReadData_Demo {
public static void main(String args[]) {
FileReader fr = null;
try {
File file = new File("file.txt");
fr = new FileReader(file); char [] a = new char[50];
fr.read(a); // reads the content to the array
for(char c : a)
System.out.print(c); // prints the characters one by one
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
fr.close();
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
}
试用资源(也称为自动资源管理)是Java 7中引入的一种新的异常处理机制,它自动关闭try catch块内使用的资源。
要使用此语句,只需在括号内声明所需的资源,并且创建的资源将在块的末尾自动关闭。 以下是try-with-resources语句的语法。
语法
try(FileReader fr = new FileReader("file path")) {
// use the resource
} catch () {
// body of catch
}
}
以下是使用try-with-resources语句读取文件中的数据的程序。
例子
import java.io.FileReader;
import java.io.IOException;
public class Try_withDemo {
public static void main(String args[]) {
try(FileReader fr = new FileReader("E://file.txt")) {
char [] a = new char[50];
fr.read(a); // reads the contentto the array
for(char c : a)
System.out.print(c); // prints the characters one by one
} catch (IOException e) {
e.printStackTrace();
}
}
}
在try-with-resources声明的同时,要牢记以下几点。
- 要使用带有try-with-resources语句的类,它应该实现AutoCloseable接口,并在运行时自动调用close()方法。
- 您可以在try-with-resources语句中声明多个类。
- 当您在try-with-resources语句的try块中声明多个类时,这些类将按相反的顺序关闭。
- 除了括号内的资源声明之外,所有内容都与try块的正常try / catch块相同。
- 在try中声明的资源在try-block开始之前被实例化。
- 在try块中声明的资源被隐式声明为final。
用户自定义异常
您可以在Java中创建自己的例外。 编写自己的异常类时请牢记以下几点 -
- 所有异常都必须是Throwable的子类。
- 如果您想编写一个由Handle或Declare Rule自动执行的checked异常,则需要扩展Exception类。
- 如果您想编写运行时异常,则需要扩展RuntimeException类。
我们可以像下面那样定义我们自己的Exception类 -
class MyException extends Exception {
}
您只需要扩展预定义的Exception类来创建您自己的Exception。 这些被认为是检查例外。 以下InsufficientFundsException类是用户定义的异常,它扩展了Exception类,使其成为检查异常。 异常类就像任何其他类一样,包含有用的字段和方法。
例子
// File Name InsufficientFundsException.java
import java.io.*;
public class InsufficientFundsException extends Exception {
private double amount;
public InsufficientFundsException(double amount) {
this.amount = amount;
}
public double getAmount() {
return amount;
}
}
为了演示使用我们的用户定义的异常,以下CheckingAccount类包含一个引发InsufficientFundsException的withdraw()方法。
// File Name CheckingAccount.java
import java.io.*;
public class CheckingAccount {
private double balance;
private int number;
public CheckingAccount(int number) {
this.number = number;
}
public void deposit(double amount) {
balance += amount;
}
public void withdraw(double amount) throws InsufficientFundsException {
if(amount <= balance) {
balance -= amount;
}else {
double needs = amount - balance;
throw new InsufficientFundsException(needs);
}
}
public double getBalance() {
return balance;
}
public int getNumber() {
return number;
}
}
以下BankDemo程序演示调用CheckingAccount的deposit()和withdraw()方法。
// File Name BankDemo.java
public class BankDemo {
public static void main(String [] args) {
CheckingAccount c = new CheckingAccount(101);
System.out.println("Depositing $500...");
c.deposit(500.00);
try {
System.out.println("\nWithdrawing $100...");
c.withdraw(100.00);
System.out.println("\nWithdrawing $600...");
c.withdraw(600.00);
} catch (InsufficientFundsException e) {
System.out.println("Sorry, but you are short $" + e.getAmount());
e.printStackTrace();
}
}
}
编译所有上述三个文件并运行BankDemo。 这将产生以下结果 −
Depositing $500... Withdrawing $100... Withdrawing $600... Sorry, but you are short $200.0 InsufficientFundsException at CheckingAccount.withdraw(CheckingAccount.java:25) at BankDemo.main(BankDemo.java:13)
通用异常
在Java中,可以定义两个异常和错误。
- JVM异常 - 这些是JVM专有或逻辑抛出的异常/错误。 示例:NullPointerException,ArrayIndexOutOfBoundsException,ClassCastException。
- 程序例外 - 这些例外由应用程序或API程序员显式引发。 示例:IllegalArgumentException,IllegalStateException。
内部类
Java 内部类
在本章中,我们将讨论Java的内部类。
嵌套类
在Java中,就像方法一样,一个类的变量也可以有另一个类作为它的成员。 在Java中允许在另一个类中编写一个类。 写入的类称为嵌套类,包含内部类的类称为外部类。
语法
以下是编写嵌套类的语法。 这里,类Outer_Demo是外部类,Inner_Demo类是嵌套类。
class Outer_Demo {
class Nested_Demo {
}
}
嵌套类分为两种类型 -
- 非静态嵌套类 - 它们是类的非静态成员。
- 静态嵌套类 - 它们是类的静态成员。
内部类(非静态嵌套类)
内部类是Java中的一种安全机制。 我们知道一个类不能与私有访问修饰符相关联,但如果我们将该类作为其他类的成员,那么内部类可以变为私有。 这也被用来访问一个班级的私人成员。
内部类有三种类型,具体取决于您如何以及在何处定义它们。 他们是 -
- 内部类
- 方法本地内部类
- 匿名内部类
内部类
创建一个内部类非常简单。 你只需要在课堂上写一个类。 与类不同,内部类可以是私有的,并且一旦声明内部类是私有的,就不能从类之外的对象访问内部类。
以下是创建内部类并访问它的程序。 在给定的例子中,我们使内部类是私有的,并通过方法访问类。
例子
class Outer_Demo {
int num;
// inner class
private class Inner_Demo {
public void print() {
System.out.println("This is an inner class");
}
}
// Accessing he inner class from the method within
void display_Inner() {
Inner_Demo inner = new Inner_Demo();
inner.print();
}
}
public class My_class {
public static void main(String args[]) {
// Instantiating the outer class
Outer_Demo outer = new Outer_Demo();
// Accessing the display_Inner() method.
outer.display_Inner();
}
}
在这里你可以观察到Outer_Demo是外部类,Inner_Demo是内部类,display_Inner()是我们正在实例化内部类的方法,并且这个方法是从main方法调用的。
如果你编译并执行上述程序,你会得到以下结果 -
输出
This is an inner class.
访问私人成员
如前所述,内部类也用于访问类的私有成员。 假设一个班级有私人成员访问他们。 写一个内部类,从内部类中的方法返回私有成员,比如getValue(),最后从另一个类(你想从中访问私有成员)调用内部的getValue()方法类。
要实例化内部类,最初必须实例化外部类。 此后,使用外部类的对象,以下是您可以实例化内部类的方式。
Outer_Demo outer = new Outer_Demo(); Outer_Demo.Inner_Demo inner = outer.new Inner_Demo();
以下程序显示如何使用内部类访问类的私有成员。
例子
class Outer_Demo {
// private variable of the outer class
private int num = 175;
// inner class
public class Inner_Demo {
public int getNum() {
System.out.println("This is the getnum method of the inner class");
return num;
}
}
}
public class My_class2 {
public static void main(String args[]) {
// Instantiating the outer class
Outer_Demo outer = new Outer_Demo();
// Instantiating the inner class
Outer_Demo.Inner_Demo inner = outer.new Inner_Demo();
System.out.println(inner.getNum());
}
}
如果你编译并执行上述程序,你会得到以下结果 -
This is the getnum method of the inner class: 175
方法本地内部类
在Java中,我们可以在方法中编写一个类,这将是一个本地类型。 像局部变量一样,内部类的范围在方法内受到限制。
方法局部内部类只能在定义内部类的方法中实例化。 以下程序显示如何使用方法本地内部类。
例子
public class Outerclass {
// instance method of the outer class
void my_Method() {
int num = 23;
// method-local inner class
class MethodInner_Demo {
public void print() {
System.out.println("This is method inner class "+num);
}
} // end of inner class
// Accessing the inner class
MethodInner_Demo inner = new MethodInner_Demo();
inner.print();
}
public static void main(String args[]) {
Outerclass outer = new Outerclass();
outer.my_Method();
}
}
如果你编译并执行上述程序,你会得到以下结果 -
输出
This is method inner class 23
匿名内部类
没有类名的内部类被称为匿名内部类。 在匿名内部类的情况下,我们同时声明并实例化它们。 通常,只要您需要重写类或接口的方法,就会使用它们。 匿名内部类的语法如下 -
语法
AnonymousInner an_inner = new AnonymousInner() {
public void my_method() {
........
........
}
};
以下程序显示如何使用匿名内部类来重写类的方法。
例子
abstract class AnonymousInner {
public abstract void mymethod();
}
public class Outer_class {
public static void main(String args[]) {
AnonymousInner inner = new AnonymousInner() {
public void mymethod() {
System.out.println("This is an example of anonymous inner class");
}
};
inner.mymethod();
}
}
如果你编译并执行上述程序,你会得到以下结果 -
输出
This is an example of anonymous inner class
以同样的方式,你可以重写具体类的方法以及使用匿名内部类的接口。
匿名内部类作为参数
通常,如果一个方法接受一个接口的对象,一个抽象类或一个具体类,那么我们可以实现接口,扩展抽象类,并将对象传递给方法。 如果它是一个类,那么我们可以直接将它传递给该方法。
但在所有这三种情况下,您都可以将匿名内部类传递给该方法。 这是传递匿名内部类作为方法参数的语法 -
obj.my_Method(new My_Class() {
public void Do() {
.....
.....
}
});
以下程序显示如何将匿名内部类作为方法参数传递。
例子
// interface
interface Message {
String greet();
}
public class My_class {
// method which accepts the object of interface Message
public void displayMessage(Message m) {
System.out.println(m.greet() +
", This is an example of anonymous inner class as an argument");
}
public static void main(String args[]) {
// Instantiating the class
My_class obj = new My_class();
// Passing an anonymous inner class as an argument
obj.displayMessage(new Message() {
public String greet() {
return "Hello";
}
});
}
}
如果你编译并执行上述程序,你会得到以下结果 -
输出
Hello, This is an example of anonymous inner class as an argument
静态嵌套类
静态内部类是一个嵌套类,它是外部类的静态成员。 可以在不使用其他静态成员实例化外部类的情况下访问它。 就像静态成员一样,静态嵌套类无法访问外部类的实例变量和方法。 静态嵌套类的语法如下 -
语法
class MyOuter {
static class Nested_Demo {
}
}
实例化一个静态嵌套类与实例化一个内部类有点不同。 以下程序显示如何使用静态嵌套类。
例子
public class Outer {
static class Nested_Demo {
public void my_method() {
System.out.println("This is my nested class");
}
}
public static void main(String args[]) {
Outer.Nested_Demo nested = new Outer.Nested_Demo();
nested.my_method();
}
}
如果你编译并执行上述程序,你会得到以下结果 -
输出
This is my nested class