-

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保证是一次写入,随时随地运行。

Java是 -

Java历史

詹姆斯·戈斯林(James Gosling)于1991年6月发起Java语言项目,用于他的许多机顶盒项目之一。在Gosling办公室外面的一棵橡树之后,这种语言最初叫做“橡树”,也是以“绿色”的名字命名的,后来被从Java列表中重新命名为随机单词。

Sun在1995年发布了第一个公共实现,就像Java 1.0一样。它承诺了一次写入,无处不在(WORA),在流行的平台上提供免费的运行时间。

2006年11月13日,Sun根据GNU通用公共许可证(GPL)的规定,将大量Java作为免费和开源软件发布。

2007年5月8日,Sun完成了这个过程,使得所有的Java的核心代码都是免费的和开源的,除了Sun没有版权的一小部分代码之外。

你需要的工具

对于执行本教程中探讨的示例,您将需要一个至少64 MB RAM(推荐128 MB RAM)的Pentium 200-MHz计算机。

您还需要以下软件 -

本教程将提供使用Java创建GUI,网络和Web应用程序的必要技能。

尝试选项

我们为您提供了一个在线编译和执行可用代码的选项。只需点击代码窗口右上角的尝试 ”按钮即可编译并执行可用的代码。有一些不能在线执行的例子,所以我们跳过了这些例子。

public class MyFirstJavaProgram {

   public static void main(String []args) {
      System.out.println("Hello World");
   }
} 

可能有一种情况,您看不到编译/执行代码的结果。在这种情况下,您可以使用编译弹出窗口中可用的执行按钮重新尝试编译并执行代码

下一步是什么?

下一章将指导您如何获取Java及其文档。最后,它指示您如何安装Java并准备开发Java应用程序的环境。

Java - 环境设置

在本章中,我们将探讨如何为Java建立一个和谐的环境。

在线运行

我们已经在线设置了Java编程环境,因此可以在线编译和执行所有可用的示例。你可以学习的同时,在线验证程序。随意修改任何示例并在线执行。

使用我们的在线编译器可在尝试下面的例子CodingGround

public class MyFirstJavaProgram {

   public static void main(String []args) {
      System.out.println("Hello World");
   }
} 

对于本教程中给出的大多数示例,您将在右上角的网站代码部分找到一个Try it选项,该部分将带您进入在线编译器。所以只是利用它,享受你的学习。

本地环境设置

如果您仍然愿意为Java编程语言设置环境,那么本节将介绍如何在您的计算机上下载和设置Java。以下是设置环境的步骤。

Java SE可以从链接下载Java免费获得您可以根据您的操作系统下载一个版本。

按照说明下载Java并运行.exe在您的机器上安装Java。一旦在机器上安装了Java,您将需要设置环境变量来指向正确的安装目录 -

设置Windows的路径

假设您已经在c: Program Files java jdk目录中安装了Java -

设置Linux,UNIX,Solaris,FreeBSD的路径

环境变量PATH应设置为指向Java二进制文件的安装位置。参考你的shell文档,如果你有麻烦这样做。

例如,如果您使用bash作为您的shell,那么您可以将以下行添加到“.bashrc:export PATH = / path / to / java:$ PATH”的末尾。

流行的Java编辑器

要编写Java程序,您需要一个文本编辑器。市场上还有更复杂的IDE。但是现在,您可以考虑以下之一 -

下一步是什么?

下一章将教您如何编写和运行您的第一个Java程序以及开发应用程序所需的Java中的一些重要基本语法。

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
   }
}

我们来看看如何保存文件,编译和运行程序。请遵循后续步骤 -

输出

C:> javac MyFirstJavaProgram.java
C:> java MyFirstJavaProgram 
Hello World

基本语法

关于Java程序,请记住以下几点:

Java标识符

所有Java组件都需要名称。用于类,变量和方法的名称称为标识符

在Java中,有几个要记住的标识符。他们如下 -

Java修饰符

像其他语言一样,可以通过使用修饰符修改类,方法等。有两类修饰符 -

我们将在下一节中详细介绍修饰符。

Java变量

以下是Java中的变量类型 -

Java数组

数组是存储相同类型的多个变量的对象。但是,数组本身就是堆上的一个对象。我们将在下一章中研究如何声明,构造和初始化。

Java枚举

枚举在Java 5.0中引入。枚举将变量限制为只有几个预定义值。枚举列表中的值被称为枚举。

使用枚举可以减少代码中的错误数量。

例如,如果我们考虑一个新鲜果汁店的申请,那么可以将玻璃尺寸限制在小,中,大。这将确保它不允许任何人订购除中小型以外的任何尺寸。

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中的保留字。这些保留字不能用作常量或变量或任何其他标识符名称。

抽象 break boolean break
byte 案件 catch char
class const continute default
do double other enum
延伸 最后 最后 float
对于 go 如果 工具
进口 实例 int 接口
long 本地人 new
private protect public return
short 静态的 strictfp
switch 同步 this throw
投掷 短暂的 尝试 无效
挥发性

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中,类可以从类派生。基本上,如果您需要创建一个新类,并且这里已经是一个需要一些代码的类,那么可以从已经存在的代码中导出新的类。

这个概念允许您重用现有类的字段和方法,而无需重写新类中的代码。在这种情况下,现有类称为类,派生类称为子类

接口

在Java语言中,可以将接口定义为对象之间如何进行通信的契约。接口在继承的概念上起着至关重要的作用。

接口定义了派生类(子类)应该使用的方法。但是方法的实现完全取决于子类。

下一步是什么?

下一节将介绍Java编程中的对象和类。在会话结束时,您将能够清楚地了解到什么是对象以及什么是Java中的类。

Java - 对象和类

Java是面向对象的语言。作为具有面向对象功能的语言,Java支持以下基本概念 -

在本章中,我们将研究概念 - 类和对象。

Java中的对象

现在让我们深入了解什么是对象。如果我们考虑现实世界,我们可以在我们周围找到许多对象,汽车,狗,人类等等。所有这些对象都有一种状态和行为。

如果我们考虑一只狗,那么它的状态是 - 名称,品种,颜色,行为 - 吠叫,拖尾,跑步。

如果将软件对象与真实对象进行比较,则它们具有非常相似的特性。

软件对象也具有状态和行为。软件对象的状态存储在字段中,行为通过方法显示。

因此,在软件开发中,方法对对象的内部状态进行操作,并且通过方法进行对象到对象的通信。

Java中的类

类是创建单个对象的蓝图。

以下是课程的样本。

public class Dog {
   String breed;
   int ageC
   String color;

   void barking() {
   }

   void hungry() {
   }

   void sleeping() {
   }
}

类可以包含以下任何变量类型。

一个类可以有多种方法来访问各种方法的值。在上面的例子中,barking(),hungry()和sleeping()是方法。

以下是在查看Java语言的类时需要探讨的一些重要主题。

构造函数

在探讨课程时,最重要的一个主题是构造函数。每个类都有一个构造函数。如果我们没有为类创建一个构造函数,那么Java编译器会为该类建立一个默认构造函数。

每次创建一个新对象时,至少会调用一个构造函数。构造函数的主要规则是它们应该与类具有相同的名称。一个类可以有多个构造函数。

以下是一个构造函数的例子 -

public class Puppy {
   public Puppy() {
   }

   public Puppy(String name) {
      // This constructor has one parameter, name.
   }
}

Java还支持Singleton类,您将只能创建一个类的一个实例。

- 我们有两种不同类型的构造函数。我们将在随后的章节中详细探讨构造函数。

创建对象

如前所述,一个类提供了对象的蓝图。所以基本上,一个对象是从一个类创建的。在Java中,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

源文件声明规则

作为本节的最后一部分,现在来看看源文件声明规则。在源文件中声明类,导入语句和语句时,这些规则至关重要

类有几个访问级别,有不同类型的类; 抽象类,最终类等。我们将在访问修饰符一章中解释所有这些。

除了上述类型的类之外,Java还有一些名为Inner类和Anonymous类的特殊类。

Java包

简单来说,它是对类和接口进行分类的一种方法。在Java中开发应用程序时,将会写入数百个类和接口,因此对这些类进行分类是必须的,并且使生活更容易。

进口报关单

在Java中,如果给出了包含包和类名称的完全限定名称,则编译器可以轻松找到源代码或类。导入语句是为编译器找到该特定类的正确位置的一种方式。

例如,以下行将要求编译器加载目录java_installation / java / io中可用的所有类 -

import java.io.*;

一个简单的案例研究

对于我们的案例研究,我们将创建两个类。他们是员工和员工测试。

首先打开记事本并添加以下代码。记住这是Employee类,该类是一个公共类。现在,保存名为Employee.java的源文件。

Employee类有四个实例变量 - 名称,年龄,指定和工资。该类有一个明确定义的构造函数,它接受一个参数。

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);
   }
}

如本教程前面所述,处理从主要方法开始。因此,为了让我们运行这个Employee类,应该有一个主要的方法,应该创建对象。我们将为这些任务创建一个单独的类。

以下是EmployeeTest类,它创建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 - 基本数据类型

变量只不过是保存存储值的内存位置。这意味着当您创建一个变量时,您可以在内存中保留一些空间。

基于变量的数据类型,操作系统分配内存并决定可以存储在预留内存中的内容。因此,通过为变量分配不同的数据类型,可以在这些变量中存储整数,小数或字符。

Java中有两种可用的数据类型 -

原始数据类型

Java支持八种基本数据类型。原始数据类型由语言预定义并由关键字命名。现在让我们详细研究八个基本的数据类型。

字节

short

int

float

boolean

char

参考数据类型

Java文字

字面值是固定值的源代码表示。它们直接在代码中进行表示,无需任何计算。

文字可以分配给任何基本类型的变量。例如 -

byte a = 68;
char a = "A"

字节,int,long和short可以表示为十进制(10位),十六进制(16位)或八进制(8位)数字系统。

前缀0用于指示八进制,前缀0x表示十六进制,当使用这些数字系统的文字时。例如 -

int decimal = 100;
int octal = 0144;
int hexa =  0x64;

Java中的字符string字面值通过在一对双引号之间包含一系列字符而被指定为大多数其他语言。字符string文字的例子是 -

"Hello World"
"two
lines"
""This is in quotes""

字符string和字符类型的文字可以包含任何Unicode字符。例如 -

char a = "u0001";
String a = "u0001";

Java语言对于String和char文字也支持很少的特殊转义序列。他们是 -

符号 字符代表
n 换行(0x0a)
r 回车(0x0d)
F Formfeed(0x0c)
b 退格(0x08)
s 空格(0x20)
t 标签
双引号
" 单引号
反斜杠
ddd 八进制角色(ddd)
uxxxx 十六进制UNICODE字符(xxxx)

下一步是什么?

本章介绍了各种数据类型。下一个主题解释不同的变量类型及其用法。这将使您很好地了解如何在Java类,接口等中使用它们。

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

实例变量

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

类/静态变量

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访问

下一步是什么?

本章中已经使用了访问修饰符(public和private)。下一章将详细介绍访问修饰符和非访问修饰符。

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提供了许多非访问修饰符来实现许多其他功能。

下一步是什么?

在下一节中,我们将探讨Java语言中使用的基本运算符。本章将为您介绍如何在应用程序开发过程中使用这些操作符。

Java - 基本操作符

Java提供了一组丰富的操作符来操纵变量。我们可以将所有Java运算符分成以下组 -

算术运算符

算术运算符与数学表达式中使用的代数方法相同。下表列出了算术运算符 -

假设整数变量A保持10,变量B保持20,则 -

显示示例

操作符 描述
+(加法) 在操作符的两边添加值。 A + B将给予30
- (减) 从左手操作数减去右手操作数。 A - B会给-10
*(乘法) 在运算符的任一侧乘以值。 A * B将给予200
/(司) 用右手操作数除以左手操作数。 B / A将给予2
%(模量) 用右手操作数除以左手操作数,并返回余数。 B%A将给0
++(增量) 将操作数的值增加1。 B ++给了21
- (减) 将操作数的值减少1。 B--给了19

关系运算符

Java语言支持以下关系运算符。

假设变量A保持10,变量B保持20,则 -

显示示例

操作符 描述
==(等于) 检查两个操作数的值是否相等,如果是,则条件成立。 (A == B)不正确。
!=(不等于) 检查两个操作数的值是否相等,如果值不等于条件成为真。 (A!= B)是真的。
>(大于) 检查左操作数的值是否大于右操作数的值,如果是,则条件成为真。 (A> B)不正确。
(少于) 检查左操作数的值是否小于右操作数的值,如果是,则条件成为真。 (A <B)是真的。
> =(大于或等于) 检查左操作数的值是否大于或等于右操作数的值,如果是,则条件成为真。 (A> = B)不正确。
<=(小于或等于) 检查左操作数的值是否小于或等于右操作数的值,如果是,则条件成为真。 (A <= B)是真的。

按位运算符

Java定义了几个按位运算符,可以将其应用于整数类型long,int,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,则 -

显示示例

操作符 描述
&(按位和) 如果二进制AND运算符存在于两个操作数中,则二进制AND运算符将对结果复制一位。 (A和B)将给出12是0000 1100
| (按位或) 二进制OR运算符如果存在于任一操作数中,则复制一位。 (A | B)将给出61,其为0011 1101
^(按位异或) 二进制XOR操作符复制该位,如果它设置在一个操作数中,而不是两者。 (A ^ B)将给出49,其为0011 0001
(按位称赞) 二进制补码运算符是一元的,具有“翻转”位的作用。 (A)将给出-61,由于有符号的二进制数,它是2 0的补码形式的1100 0011。
<<(左移) 二进制左移操作符。左操作数值左移由右操作数指定的位数。 A << 2将给出240是1111 0000
>>(右移) 二进制右移操作符。左操作数值被右操作数指定的位移动。 A >> 2将给出15是1111
>>>(零填补右移) 右移零填充操作符。左操作数值右移由右操作数指定的位数,移位值用零填充。 A >>> 2将给出15是0000 1111

逻辑运算符

下表列出了逻辑运算符 -

假设布尔变量A为真,变量B为假,则 -

显示示例

操作符 描述
&&(逻辑和) 称为逻辑AND运算符。如果两个操作数都不为零,则条件成立。 (A && B)是假的
|| (逻辑或) 称为逻辑或运算符。如果两个操作数中的任何一个非零,则条件成立。 (A || B)是真的
(逻辑不) 称为逻辑非运算符。用于反转其操作数的逻辑状态。如果条件为真,则逻辑NOT运算符将为false。 !(A && B)是真的

作业人员

以下是Java语言支持的赋值运算符 -

显示示例

操作符 描述
= 简单赋值运算符。将右侧操作数的值分配给左侧操作数。 C = A + B将A的值分配给C
+ = 添加AND赋值运算符。它将右操作数添加到左操作数,并将结果分配给左操作数。 C + = A等价于C = C + A
- = 减去AND赋值运算符。它从左操作数中减去右操作数,并将结果分配给左操作数。 C - = A等价于C = C-A
* = 乘以AND赋值运算符。它将右操作数与左操作数相乘,并将结果分配给左操作数。 C * = A等价于C = C * A
/ = 除以AND赋值运算符。它将左操作数与右操作数分开,并将结果分配给左操作数。 C / = A等价于C = C / A
%= 模数和赋值运算符。它需要使用两个操作数的模数,并将结果分配给左操作数。 C%= A等价于C = C%A
<< = 左移和赋值运算符。 C << = 2与C = C << 2相同
>> = 右移和赋值运算符。 C&= 2与C = C&2相同
&= 按位AND赋值运算符。 C >> = 2与C = C >> 2相同
^ = 按位异或运算符和赋值运算符。 C ^ = 2与C = C ^ 2相同
| = 按位包含OR和赋值运算符。 C | = 2与C = C |相同 2

杂项经营者

Java语言支持的其他操作系统还不多。

条件运算符(?:)

条件运算符也称为三进制运算符该运算符由三个操作数组成,用于评估布尔表达式。运算符的目标是决定哪个值应该分配给变量。操作符写为 -

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)

如果由操作符左侧的变量引用的对象通过右侧的类/接口类型的IS-A检查,则结果将为真。以下是一个例子 -

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 );
   }
}

输出结果如下 -

输出

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 );
   }
}

输出结果如下 -

输出

true

Java运算符的优先级

运算符优先级决定表达式中术语的分组。这会影响表达式的评估。某些运算符的优先级高于其他运算符; 例如,乘法运算符的优先级高于加法运算符 -

例如,x = 7 + 3 * 2; 这里x被分配13,而不是20,因为operator *的优先级高于+,所以它首先被乘以3 * 2,然后加到7中。

这里,优先级最高的运算符出现在表的顶部,最底层的运算符出现在底部。在一个表达式中,先优先级较高的算子。

类别 操作符 关联性
后缀 >()[]。(点运算符) 左到右
一元 > ++ - - ! 右到左
乘法 > * / 左到右
添加剂 > + - 左到右
转移 >>> >>> << 左到右
关系型 >>> = <<= 左到右
平等 > ==!= 左到右
按位AND >& 左到右
按位XOR > ^ 左到右
按位OR > | 左到右
逻辑与 > && 左到右
逻辑或 > || 左到右
有条件的 ?: 右到左
分配 > = + = - = * = / =%= >> = << =&= ^ = | = 右到左

下一步是什么?

下一章将介绍Java编程中的循环控制。本章将介绍各种类型的循环,以及如何在Java程序开发中使用这些循环以及它们正在使用的目的。

Java - 循环控制

当您需要执行一段代码多次时可能会出现这种情况。一般来说,语句依次执行:函数中的第一个语句先执行,后跟第二个语句,依此类推。

编程语言提供了允许更复杂的执行路径的各种控制结构。

一个循环语句允许我们执行的语句多次声明或组,下面是一个循环语句的一般形式在大多数编程语言-

循环架构

Java编程语言提供以下类型的循环来处理循环需求。单击以下链接以查看其详细信息。

没有 循环和描述
1 while循环

在给定条件为真时,重复一个语句或一组语句。它在执行循环体之前测试状态。

2 for循环

多次执行一系列语句,并缩写管理循环变量的代码。

3 do... while循环

像while语句一样,除了它测试循环体结尾的条件。

循环控制语句

循环控制语句从其正常顺序更改执行。当执行离开范围时,在该范围内创建的所有自动对象都将被销毁。

Java支持以下控制语句。单击以下链接以查看其详细信息。

没有 控制声明和说明
1 break

终止循环切换语句,并将执行转移到循环或切换后立即执行。

2 continute

导致循环跳过其身体的剩余部分,并在重申之前立即重新测试其状态。

在Java中增强for循环

从Java 5开始,引入了增强的for循环。这主要用于遍历元素的集合,包括数组。

用法

以下是增强for循环的语法 -

for(declaration : expression) {
   // Statements
}

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("
");
      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 - 判断

判断结构具有一个或多个要由该程序评估或测试的条件,以及如果条件被确定为真,将执行的陈述或声明,以及可选地,如果条件被确定则要执行的其他语句是假的

以下是大多数编程语言中的典型判断结构的一般形式 -

做决定

Java编程语言提供以下类型的判断语句。单击以下链接以查看其详细信息。

没有 声明和说明
1 if语句

一个if语句由一个布尔表达式,后跟一个或多个语句组成。

2 if... else语句

一个if语句可以跟随一个可选的else语句,当布尔表达式为false时,该语句将执行。

3 嵌套if语句

您可以在另一个ifelse语句中使用一个ifelse if语句

4 switch

switch语句允许一个变量来针对值的列表平等进行测试。

的?:操作符

我们已经涵盖了条件运算符?在上一章中可以用来替换if else else语句。它具有以下一般形式 -

Exp1 ? Exp2 : Exp3;

其中Exp1,Exp2和Exp3是表达式。注意冒号的使用和位置。

要确定整个表达式的值,首先评估exp1。

下一步是什么?

在下一章中,我们将探讨Java语言中的Number类(在java.lang包中)及其子类。

我们将研究一些您将使用这些类的实例的情况,而不是原始数据类型,以及类别,例如格式化,数学函数,您需要了解何时使用数字。

Java - 数字类

通常,当我们使用Numbers时,我们使用原始数据类型,如byte,int,long,double等

int i = 5000;
float gpa = 13.65;
double mask = 0xaf;

然而,在开发中,我们遇到需要使用对象而不是基本数据类型的情况。为了实现这一点,Java提供了包装类

所有包装类(整数,长,字节,双,浮点,短)是抽象类Number的子类。

数字类

包装类的对象包含或包装其各自的基本数据类型。将原始数据类型转换为对象称为装箱,并由编译器进行注意。因此,在使用包装类时,您只需要将原始数据类型的值传递给Wrapper类的构造函数。

并且Wrapper对象将被转换回原始数据类型,此过程称为取消装箱。号码类是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类的所有子类实现的实例方法的列表:

没有 方法和说明
1 xxxValue()

将此 Number对象的值转换为xxx数据类型并返回。

2 相比于()

比较 Number对象的说法。

3 等于()

确定数字对象是否等于参数。

4 的价值()

返回一个保存指定基元值的整数对象。

5 toString()

返回一个表示指定int或Integer值的String对象。

6 parseInt()

该方法用于获取某个字符string的原始数据类型。

7 abs()

返回参数的绝对值。

8 ceil()

返回大于或等于参数的最小整数。以double身份退回

9 地板()

返回小于或等于参数的最大整数。以double身份退回

10 rint()

返回与参数最接近的整数。以double身份退回

11 回合()

返回最接近的long或int,如方法返回类型所指示的那样。

12 min()

返回两个参数中较小的一个。

13 max()

返回两个参数中较大的一个。

14 exp()

返回自然对数的基数e,取决于参数的幂。

15 log()

返回参数的自然对数。

16 pow()

将第一个参数的值返回到第二个参数的幂。

17 sqrt()

返回参数的平方根。

18 罪()

返回指定double值的正字符string值。

19 cos()

返回指定double值的余字符string值。

20 谭()

返回指定double值的正切值。

21 asin()

返回指定double值的反正字符string值。

22 acos()

返回指定double值的反余字符string。

23 晒黑()

返回指定double值的反正切值。

24 atan2()

将直角坐标(x,y)转换为极坐标(r,θ)并返回θ。

25 toDegrees()

将参数转换为度。

26 toRadians()

将参数转换为弧度。

27 随机()

返回随机数。

下一步是什么?

在下一节中,我们将介绍Java中的Character类。您将学习如何使用Java中的对象字符和原始数据类型char。

Java - 字符类

通常,当我们使用字符时,我们使用原始数据类型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对象。例如,如果您将原始字符传递给期望对象的方法,则编译器会自动将char转换为字符。此功能称为自动装箱或拆箱,如果转换成另一种方式。

// 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");

转义序列

前面带有反斜杠()的字符是一个转义序列,对编译器有特殊的含义。

在本教程中,System.out.println()语句中经常使用换行字符( n),以便在打印字符string后前进到下一行。

下表显示了Java转义序列 -

逃脱序列 描述
t 此时在文本中插入一个选项卡。
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类的所有子类实现的重要实例方法的列表 -

没有 方法和说明
1 isLetter()

确定指定的char值是否为字母。

2 isDigit()

确定指定的char值是否为数字。

3 isWhitespace()

确定指定的char值是否为空格。

4 isUpperCase()

确定指定的char值是否为大写。

5 isLowerCase()

确定指定的char值是否为小写。

6 toUpperCase()

返回指定字符值的大写形式。

7 toLowerCase()

返回指定字符值的小写形式。

8 toString()

返回一个String对象,表示指定的字符值,即一个字符的字符string。

有关方法的完整列表,请参阅java.lang.Character API规范。

下一步是什么?

在下一节中,我们将介绍Java中的String类。您将学习如何有效地声明和使用Strings以及String类中的一些重要方法。

Java - 字符string类

在Java编程中广泛使用的字符string是字符序列。在Java编程语言中,字符string被视为对象。

Java平台提供了String类来创建和操作字符string。

创建字符string

创建字符string的最直接的方式是写 -

String greeting = "Hello world!";

无论何时遇到代码中的字符string字面值,编译器会在这种情况下创建一个String对象,其值为“Hello world!”。

与任何其他对象一样,您可以使用new关键字和构造函数来创建String对象。String类有11个构造函数,允许您使用不同的源(例如字符数组)来提供字符string的初始值。

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对象就无法更改。如果有必要对字符string进行大量修改,那么您应该使用String Buffer&String Builder类。

字符string长度

用于获取有关对象的信息的方法称为访问器方法一个可以使用字符string的访问器方法是length()方法,它返回字符string对象中包含的字符数。

以下程序是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

String类包括一个连接两个字符string的方法 -

string1.concat(string2);

这将返回一个新的字符string,该字符string是string1,最后添加了string2。您也可以使用concat()方法与字符string文字,如 -

"My name is ".concat("Zara");

字符string通常与+运算符连接,如 -

"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

创建格式字符string

您可以使用printf()和format()方法打印具有格式化数字的输出。String类具有等效的类方法format(),它返回String对象而不是PrintStream对象。

使用String的静态格式()方法可以创建一个可重用的格式化字符string,而不是一次性的print语句。例如,而不是 -

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方法

以下是String类支持的方法列表 -

没有 方法和说明
1 char charAt(int index)

返回指定索引处的字符。

2 int compareTo(Object o)

将此String与另一个对象进行比较。

3 int compareTo(String anotherString)

按字典顺序比较两个字符string。

4 int compareToIgnoreCase(String str)

按字典顺序比较两个字符string,忽略病例差异。

5 String concat(String str)

将指定的字符string连接到该字符string的末尾。

6 boolean contentEquals(StringBuffer sb)

当且仅当此String表示与指定的StringBuffer相同的字符序列时,才返回true。

7 static String copyValueOf(char [] data)

返回一个字符string,表示指定的数组中的字符序列。

8 static String copyValueOf(char [] data,int offset,int count)

返回一个字符string,表示指定的数组中的字符序列。

9 boolean endsWith(String suffix)

测试此字符string是否以指定的后缀结尾。

10 boolean equals(Object anObject)

将此字符string与指定对象进行比较。

11 boolean equalsIgnoreCase(String anotherString)

将此String与另一个String进行比较,忽略大小写注意事项。

12 byte getBytes()

使用平台的默认字符集将此String编码为一系列字节,将结果存储到新的字节数组中。

13 byte [] getBytes(String charsetName)

使用命名的字符集将此String编码为一系列字节,将结果存储到新的字节数组中。

14 void getChars(int srcBegin,int srcEnd,char [] dst,int dstBegin)

将此字符string中的字符复制到目标字符数组中。

15 int hashCode()

返回此字符string的哈希码。

16 int indexOf(int ch)

返回指定字符第一次出现的字符string内的索引。

17 int indexOf(int ch,int fromIndex)

返回指定字符第一次出现的字符string内的索引,以指定的索引开始搜索。

18 int indexOf(String str)

返回指定子字符string第一次出现的字符string内的索引。

19 int indexOf(String str,int fromIndex)

返回指定子string的第一次出现的字符string中的索引,从指定的索引开始。

20 String intern()

返回字符string对象的规范表示。

21 int lastIndexOf(int ch)

返回指定字符的最后一次出现的字符string中的索引。

22 int lastIndexOf(int ch,int fromIndex)

返回指定字符的最后一次出现的字符string中的索引,从指定的索引开始向后搜索。

23 int lastIndexOf(String str)

返回指定子字符string最右边出现的字符string内的索引。

24 int lastIndexOf(String str,int fromIndex)

返回指定子字符string的最后一次出现的字符string中的索引,从指定索引开始向后搜索。

25 int length()

返回此字符string的长度。

26 布尔匹配(String regex)

告诉这个字符string是否与给定的正则表达式匹配。

27 boolean regionMatches(boolean ignoreCase,int toffset,String other,int ooffset,int len)

测试两个字符string区域是否相等。

28 boolean regionMatches(int toffset,String other,int ooffset,int len)

测试两个字符string区域是否相等。

29 字符string替换(char oldChar,char newChar)

返回一个新的字符string,它是用newChar替换此字符string中所有出现的oldChar的结果。

30 String replaceAll(String regex,String replacement

用给定的替换替换与给定正则表达式匹配的此字符string的每个子字符string。

31 String replaceFirst(String regex,String replacement)

用给定的替换替换与给定正则表达式匹配的此字符string的第一个子字符string。

32 String [] split(String regex)

将此字符string拆分为给定正则表达式的匹配项。

33 String [] split(String regex,int limit)

将此字符string拆分为给定正则表达式的匹配项。

34 boolean startsWith(String prefix)

测试此字符string是否以指定的前缀开头。

35 boolean startsWith(String prefix,int toffset)

测试此字符string是否以指定的前缀开头,指定一个指定的索引。

36 CharSequence subSequence(int beginIndex,int endIndex)

返回一个新的字符序列,该序列是该序列的子序列。

37 字符stringsubstring(int beginIndex)

返回一个新字符string,该字符string是此字符string的子字符string。

38 字符string子string(int beginIndex,int endIndex)

返回一个新字符string,该字符string是此字符string的子字符string。

39 char [] toCharArray()

将此字符string转换为新的字符数组。

40 String toLowerCase()

使用默认语言环境的规则将此String中的所有字符转换为小写。

41 String toLowerCase(Locale locale)

使用给定的区域设置的规则将此String中的所有字符转换为小写。

42 String toString()

此对象(已经是字符string!)本身已被返回。

43 String toUpperCase()

使用默认语言环境的规则将此字符string中的所有字符转换为大写。

44 String toUpperCase(Locale locale)

使用给定的区域设置的规则将此String中的所有字符转换为大写。

45 字符stringtrim()

返回字符string的副本,省略前导和尾随空格。

46 static String valueOf(原始数据类型x)

返回传递的数据类型参数的字符string表示形式。

Java - 数组

Java提供了一个数据结构,所述数组,其存储相同类型的元件的固定大小的连续集合。数组用于存储数据集合,但将数组视为相同类型变量的集合通常更为有用。

您可以声明一个数组变量,例如数字和数字[0],数字[1]和...,数字[99]来表示数字变量,而不是声明个别变量,例如number0,number1,...和number99个体变量。

本教程介绍如何使用索引变量声明数组变量,创建数组和处理数组。

声明数组变量

要在程序中使用数组,您必须声明一个变量来引用数组,并且必须指定变量可以引用的数组类型。这是声明数组变量的语法 -

用法

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[] 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保存十个双精度值,索引为0到9。

Java数组

处理数组

处理数组元素时,我们经常使用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引入了一个称为foreach循环或增强for循环的新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;
}

数组类

java.util.Arrays类包含用于排序和搜索数组,比较数组和填充数组元素的各种静态方法。这些方法对于所有原始类型都是重载的。

没有 方法和说明
1

public static int binarySearch(Object [] a,Object键)

使用二进制搜索算法搜索指定值的Object(Byte,Int,double等)的指定数组。在进行此调用之前,必须对数组进行排序。这将返回搜索关键字的索引,如果它包含在列表中; 否则返回( - (插入点+ 1))。

2

public static boolean equals(long [] a,long [] a2)

如果两个指定的longs数组彼此相等,则返回true。如果两个数组都包含相同数量的元素,则两个数组被认为是相等的,并且两个数组中所有对应的元素对都相等。如果两个数组相等,则返回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

日期()

此构造函数使用当前日期和时间初始化对象。

2

日期(长毫秒)

该构造函数接受一个等于从1970年1月1日午夜以来经过的毫秒数的参数。

以下是日期类的方法。

没有 方法和说明
1

布尔后(日期日期)

如果调用的Date对象包含的日期晚于date指定的日期,则返回true,否则返回false。

2

布尔之前(日期日期)

如果调用的Date对象包含早于date指定的日期,则返回true,否则返回false。

3

对象克隆()

复制调用Date对象。

4

int compareTo(日期日期)

将调用对象的值与date的值进行比较。如果值相等,则返回0。如果调用对象早于date,则返回一个负值。如果调用对象晚于日期,则返回正值。

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对象转换为字符string并返回结果。

获取当前日期和时间

这是一个非常简单的方法来获取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

日期比较

以下是比较两个日期的三种方式 -

日期格式化使用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格式代码

要指定时间格式,请使用时间模式字符string。在这种模式中,所有ASCII字母都保留为模式字母,其定义如下:

字符 描述
G 时代标志 广告
y 年份四位数 2001年
M 一个月 七月或七月
d 一个月 10
H 小时在AM / PM(112) 12
H 小时(023) 22
m 分钟小时 30
s 二分钟 55
S 毫秒 234
E 星期几 星期二
D 一年一年 360
F 一个星期的月份 2(七月二日)
w 一年 40
W 一个月 1
一个 AM / PM标记 下午
k 小时(124) 24
K 小时在AM / PM(011) 10
z 时区 东部标准时间
逃脱文本 分隔符
单引号 `

日期格式化使用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 using toString()
      String str = String.format("Current Date/Time : %tc", date );

      System.out.printf(str);
   }
}

输出结果如下 -

输出

Current Date/Time : Sat Dec 15 16:37:57 MST 2012

如果您必须多次提供日期格式化每个部分,这将会有点愚蠢。因此,格式字符string可以指示要格式化的参数的索引。

索引必须立即跟随%,并且必须由$终止。

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.printf("%1$s %2$tB %2$td, %2$tY", "Due date:", date);
   }
}

输出结果如下 -

输出

Due date: February 09, 2004

或者,您可以使用<flag。这表明应该再次使用与上一格式规范相同的参数。

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

日期和时间转换字符

字符 描述
C 完成日期和时间 星期一五月04 09:51:52 CDT 2009
F ISO 8601日期 2004-02-09
D 美国格式化日期(月/日/年) 02/09/2004
T 24小时的时间 18:05:19
r 12小时的时间 06:05:19下午
R 24小时的时间,没有秒 18:05
Y 四位数年份(领先零) 2004年
y 年份的最后两位数字(前导零) 04
C 年头两位数字(前导零) 20
B 全月份名称 二月
b 缩写月份名称 二月
m 两位数月份(前导零) 02
d 两位数的一天(带前导零) 03
e 两位数的一天(无前导零) 9
一个 完整的工作日名称 星期一
一个 缩写工作日名称 星期一
j 三位数的一年(带前导零) 069
H 两位数小时(前导零),介于00和23之间 18
k 两位数小时(不带前导零),介于0和23之间 18
一世 两位数小时(前导零),介于01和12之间 06
l 两位数小时(无前导零),介于1到12之间 6
M 两位数分钟(带前导零) 05
S 两位数秒(带前导零) 19
L 三位数毫秒(带前导零) 047
N 九位数纳秒(前导零) 047000000
P 大写上午或下午的标记 下午
p 小写上午或下午的标记 下午
z RFC 822与GMT的数字偏移 -0800
Z 时区 太平洋标准时间
s 自1970-01-01 00:00:00 GMT以来的秒数 1078884319
自1970-01-01 00:00:00 GMT以来的毫秒数 1078884319047

还有与日期和时间相关的其他有用的类。有关更多详细信息,请参阅Java Standard文档。

解析字string进入日期

SimpleDateFormat类有一些额外的方法,特别是parse(),它尝试根据给定的SimpleDateFormat对象中存储的格式来解析字符string。

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( ) + "
"); 
         Thread.sleep(5*60*10); 
         System.out.println(new Date( ) + "
"); 
      }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( ) + "
");
         
         Thread.sleep(5*60*10);
         System.out.println(new Date( ) + "
");
         
         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。这些代表着公历所定义的两个时代。

GregorianCalendar对象还有几个构造函数 -

没有 构造函数和描述
1

公历()

使用默认时区的默认语言环境创建默认的GregorianCalendar。

2

GregorianCalendar(int year,int month,int date)

构造一个GregorianCalendar,其中给定日期在默认时区中设置为默认语言环境。

3

GregorianCalendar(int year,int month,int date,int hour,int minute)

构造一个GregorianCalendar,其中给定的日期和时间为默认时区设置了默认语言环境。

4

GregorianCalendar(int year,int month,int date,int hour,int minute,int second)

构造一个GregorianCalendar,其中给定的日期和时间为默认时区设置了默认语言环境。

5

GregorianCalendar(Locale aLocale)

根据具有给定语言环境的默认时区中的当前时间创建GregorianCalendar。

6

GregorianCalendar(时区)

根据具有默认语言环境的给定时区中的当前时间创建GregorianCalendar。

7

GregorianCalendar(TimeZone zone,Locale aLocale)

根据给定时区的当前时间,使用给定的区域设置创建GregorianCalendar。

以下是GregorianCalendar类提供的几个有用的支持方法的列表 -

没有 方法和说明
1

void add(int field,int amount)

根据日历的规则,将指定的(已签名的)时间量添加到给定的时间字段中。

2

protected void computeFields()

将UTC转换为毫秒到时间字段值。

3

protected void computeTime()

覆盖日历将时间字段值转换为UTC为毫秒。

4

boolean equals(Object obj)

将此GregorianCalendar与对象引用进行比较。

5

int get(int field)

获取给定时间字段的值。

6

int getActualMaximum(int field)

给出当前日期,返回此字段可能具有的最大值。

7

int getActualMinimum(int field)

给定当前日期,返回此字段可能具有的最小值。

8

int getGreatestMinimum(int field)

如果变化,则返回给定字段的最小值。

9

日期getGregorianChange()

获取公历日历更改日期。

10

int getLeastMaximum(int field)

如果变化,则返回给定字段的最小值。

11

int getMaximum(int field)

返回给定字段的最大值。

12

日期getTime()

获取此日历的当前时间。

13

long getTimeInMillis()

获取这个日历的当前时间很长一段时间。

14

TimeZone getTimeZone()

获取时区。

15

int getMinimum(int field)

返回给定字段的最小值。

16

int hashCode()

覆盖hashCode。

17

boolean isLeapYear(int year)

确定给定年份是否是闰年。

18

void roll(int field,boolean up)

在给定时间字段上添加或减少单个时间单位,而不改变较大的字段。

19

void set(int field,int value)

设定给定值的时间字段。

20

void set(int year,int month,int date)

设置字段年,月和日期的值。

21

void set(int year,int month,int date,int hour,int minute)

设置字段年,月,日,小时和分钟的值。

22

void set(int year,int month,int date,int hour,int minute,int second)

设置字段年,月,日,小时,分和秒的值。

23

void setGregorianChange(Date date)

设置GregorianCalendar更改日期。

24

void setTime(Date date)

将该日历的当前时间设置为给定的日期。

25

void setTimeInMillis(long millis)

从给定的长值设置此日历的当前时间。

26

void setTimeZone(TimeZone value)

以给定的时区值设置时区。

27

String toString()

返回此日历的字符string表示形式。

import java.util.*;
public class GregorianCalendarDemo {

   public static void main(String args[]) {
      String months[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", 
         "Oct", "Nov", "Dec"};
      
      int year;
      // Create a Gregorian calendar initialized
      // with the current date and time in the
      // default locale and timezone.
      
      GregorianCalendar gcalendar = new GregorianCalendar();
      
      // Display current time and date information.
      System.out.print("Date: ");
      System.out.print(months[gcalendar.get(Calendar.MONTH)]);
      System.out.print(" " + gcalendar.get(Calendar.DATE) + " ");
      System.out.println(year = gcalendar.get(Calendar.YEAR));
      System.out.print("Time: ");
      System.out.print(gcalendar.get(Calendar.HOUR) + ":");
      System.out.print(gcalendar.get(Calendar.MINUTE) + ":");
      System.out.println(gcalendar.get(Calendar.SECOND));

      // Test if the current year is a leap year
      if(gcalendar.isLeapYear(year)) {
         System.out.println("The current year is a leap year");
      }else {
         System.out.println("The current year is not a leap year");
      }
   }
}

输出结果如下 -

输出

Date: Apr 22 2009
Time: 11:25:27
The current year is not a leap year

有关Calendar类中可用常量的完整列表,可以参考标准Java文档。

Java - 正则表达式

Java提供了用于与正则表达式进行模式匹配的java.util.regex包。Java正则表达式与Perl编程语言非常相似,非常容易学习。

正则表达式是一个特殊的字符序列,可以帮助您使用模式中保留的专门语法来匹配或查找其他字符string或字符string集。它们可用于搜索,编辑或操纵文本和数据。

java.util.regex包主要由以下三个类组成 -

捕获组

捕获组是将多个字符视为单个单元的一种方式。他们通过将字符的圆括号内进行分组创建。例如,正则表达式(狗)创建包含字母“D”,“O”,和“g”的单个基团。

捕获组是从左至右计算其开括号编号。在表达式((A)(B(C))),例如,有四个这样的基团 -

要了解表达式中有多少组,请在匹配器对象上调用groupCount方法。groupCount方法返回一个int,显示匹配器模式中存在的捕获组的数量。

还有一个特殊的组,组0,它始终代表整个表达式。该组不包括在groupCount报告的总数中。

以下示例说明如何从给定的字母数字字符string中找到数字字符string -

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");
      }
   }
}

输出结果如下 -

输出

Found value: This order was placed for QT3000! OK?
Found value: This order was placed for QT300
Found value: 0

正则表达式语法

这里是列出所有Java中可用的正则表达式元字符语法的表 -

子表达式 火柴
^ 匹配行的开头。
$ 匹配行尾。
匹配除换行符以外的任何单个字符。使用m选项允许它匹配换行符。
[...] 匹配括号中的任何单个字符。
[^ ...] 匹配不在括号中的任何单个字符。
一个 开始整个字符string。
z 整个字符string结束。
Z 除了允许的最终行终止符之外,整个字符string的结尾。
回覆* 匹配前面表达式的0或更多次出现。
re + 匹配1以上的事情。
回覆? 匹配0或1出现前面的表达式。
re {n} 匹配正好n个前面表达式的出现次数。
再{n,} 匹配前面表达式的n个或更多个出现次数。
re {n,m} 匹配前面表达式的n个和最多m个出现次数。
a | b 匹配a或b。
(回覆) 组合正则表达式并记住匹配的文本。
(?: 回覆) 组合正则表达式而不记住匹配的文本。
(?> re) 匹配独立模式,无需追溯。
w 匹配字符字符。
W 匹配非字符。
s 匹配空格。相当于[ t n r f]。
S 匹配非空白空间。
d 匹配数字。相当于[0-9]。
D 匹配不定式
一个 匹配字符string的开头。
Z 匹配字符string的末尾。如果存在换行符,则它将在换行符之前匹配。
z 匹配字符string的末尾。
G 匹配最后一场比赛完成的点。
n 捕获组号“n”的反参考。
b 在括号之外匹配单词边界。在括号内匹配退格(0x08)。
B 匹配非字边界。
n, t等 匹配换行符,回车符,制表符等
Q 逃避(报价)所有字符达 E。
E 结束引用开始与 Q。

匹配器类的方法

这是一个有用的实例方法的列表 -

索引方法

索引方法提供有用的索引值,可精确显示在输入字符string中找到匹配的位置 -

没有 方法和说明
1

public int start()

返回上一个匹配的起始索引。

2

public int start(int group)

返回给定组在上一个匹配操作期间捕获的子序列的开始索引。

3

public int end()

返回最后一个字符匹配后的偏移量。

4

public int end(int group)

返回在上次匹配操作期间由给定组捕获的子序列的最后一个字符之后的偏移量。

研究方法

学习方法检查输入的字符string,并返回一个布尔值,表示是否找到模式 -

没有 方法和说明
1

public boolean lookingAt()

尝试将输入序列从区域开头开始与模式相匹配。

2

public boolean find()

尝试找到匹配模式的输入序列的下一个子序列。

3

public boolean find(int start)

重新设置该匹配器,然后尝试从指定的索引开始找到匹配模式的输入序列的下一个子序列。

4

public boolean matches()

尝试将整个区域与模式进行匹配。

替代方法

替换方法是替换输入字符string中的文本的有用方法 -

没有 方法和说明
1

public Matcher appendReplacement(StringBuffer sb,String replacement)

实施非终端附加和替换步骤。

2

public StringBuffer appendTail(StringBuffer sb)

实施终端附加和替换步骤。

3

public String replaceAll(String replacement)

将与模式匹配的输入序列的每个子序列替换为给定的替换字符string。

4

public String replaceFirst(String replacement)

将与模式匹配的输入序列的第一个子序列替换为给定的替换字符string。

5

public static String quoteReplacement(String s)

返回指定String的文字替换字符string。这种方法产生一个字符string,将工作作为文字置换小号在匹配器类的appendReplacement方法。

开始和结束方法

以下是计算输入字符string中出现“cat”一词的次数的示例:

import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class RegexMatches {

   private static final String REGEX = "cat";
   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”不仅仅是一个较长的单词中的一个子字符string。它还提供了一些有用的信息,关于输入字符string中匹配发生的位置。

start方法返回给定组在前一次匹配操作中捕获的子序列的起始索引,结束返回匹配的最后一个字符的索引,加上一个。

比赛和lookAt方法

matches和lookingAt方法都尝试将输入序列与模式进行匹配。然而,区别在于匹配需要匹配整个输入序列,而lookAt则不匹配。

两种方法始终从输入字符string的开头开始。以下是说明功能的示例 -

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()

返回一个多行字符string,其中包含语法错误及其索引的描述,错误的正则表达式模式以及模式中错误索引的可视指示。

Java - 方法

Java方法是集合在一起以执行操作的语句集合。当你调用System.out。println()方法,例如,系统实际上执行几个语句,以便在控制台上显示一条消息。

现在,您将学习如何使用或不使用返回值创建自己的方法,使用或不使用参数调用方法,并在程序设计中应用方法抽象。

创建方法

考虑以下示例来解释方法的语法 -

用法

public static int methodName(int a, int b) {
   // body
}

这里,

方法定义由方法头和方法体组成。在下面的语法中也是如此 -

用法

modifier returnType nameOfMethod (Parameter List) {
   // method body
}

上面显示的语法包括 -

这是上述定义的方法的源代码,称为max()此方法采用两个参数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; 
}

方法调用

对于使用方法,应该被调用。调用方法有两种方法,即方法返回值或不返回(无返回值)。

方法调用的过程很简单。当程序调用一个方法时,程序控制被转移到被调用的方法。这个方法然后在两个条件下将控制权返回给调用者,当 -

返回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关键字允许我们创建不返回值的方法。这里,在下面的例子中我们考虑一个void方法methodRankPoints这个方法是一个void方法,它不返回任何值。调用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("
**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程序中的命令行参数是非常容易的。它们作为字符string存储在传递给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

这个关键字

是Java中的一个关键字,它被用作对当前类的对象的引用,使用实例方法或构造函数。使用这个可以引用类的成员,如构造函数,变量和方法。

-关键字是用来仅在实例方法或构造函数

这个

在一般情况下,关键字是用来-

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 instance variable
      System.out.println("value of local variable num is : "+num);
      
      // Printing the local 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()来确保该对象拥有的打开文件已关闭。

要添加一个finalizer到一个类,你只需定义finalize()方法。Java运行时每当要回收该类的对象时都会调用该方法。

在finalize()方法中,您将指定在销毁对象之前必须执行的操作。

finalize()方法有这个一般形式 -

protected void finalize( ) {
   // finalization code here
}

这里的关键字protected是一个说明符,它通过在其类之外定义的代码阻止对finalize()的访问。

这意味着你不知道什么时候甚至是finalize()将被执行。例如,如果您的程序在垃圾收集发生之前结束,则finalize()将不会执行。

Java--文件和I / O

java.io包中包含几乎所有可能需要在Java中执行输入和输出(I / O)的类。所有这些流都代表输入源和输出目标。java.io包中的流支持许多数据,如基元,对象,本地化字符等。

流可以被定义为数据序列。有两种Streams -

流

Java为与文件和网络相关的I / O提供强大但灵活的支持,但本教程涵盖与流和I / O相关的基本功能。我们将逐个看到最常用的例子 -

字节流

Java字节流用于执行8位字节的输入和输出。虽然有许多与字节流相关的类,但最常用的类是FileInputStreamFileOutputStream以下是使用这两个类将输入文件复制到输出文件中的示例 -

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.

作为下一步,编译上述程序并执行它,这将导致创建与我们在input.txt中具有相同内容的output.txt文件。所以我们把上面的代码放在CopyFile.java文件中,然后执行以下操作:

$javac CopyFile.java
$java CopyFile

字符流

Java 字节流用于执行8位字节的输入和输出,而Java 字符流用于执行16位unicode的输入和输出。虽然有许多与字符流相关的类,但最常用的类是FileReaderFileWriter虽然内部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.

作为下一步,编译上述程序并执行它,这将导致创建与我们在input.txt中具有相同内容的output.txt文件。所以我们把上面的代码放在CopyFile.java文件中,然后执行以下操作:

$javac CopyFile.java
$java CopyFile

标准流

所有编程语言都支持标准I / O,用户程序可以从键盘输入,然后在计算机屏幕上产生输出。如果您知道C或C ++编程语言,则必须注意STDIN,STDOUT和STDERR三种标准设备。类似地,Java提供以下三个标准流 -

以下是一个简单的程序,它创建了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用于写入数据至目的地。

这是处理输入和输出流的类的层次结构。

文件IO

两个重要的流是FileInputStreamFileOutputStream,这将在本教程中探讨。

FileInputStream

此流用于从文件读取数据。可以使用关键字new创建对象,并且有几种类型的构造函数可用。

以下构造函数将文件名作为字符string创建一个输入流对象以读取文件 -

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读取数据的指定字节。返回一个int。返回数据的下一个字节,如果是文件的末尾,则返回-1。

4

public int read(byte [] r)throws IOException {}

该方法将r.length字节从输入流读入数组。返回读取的总字节数。如果是文件的结尾,则返回-1。

5

public int available()throws IOException {}

给出可从该文件输入流读取的字节数。返回一个int。

还有其他重要的输入流可用,更多的细节可以参考以下链接 -

FileOutputStream

FileOutputStream用于创建文件并将数据写入其中。如果流已经不存在,流将在打开输出之前创建一个文件。

这里有两个可以用来创建FileOutputStream对象的构造函数。

以下构造函数将文件名作为字符string创建输入流对象来写入文件 -

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。

还有其他重要的输出流可用,更多的细节可以参考以下链接 -

以下是演示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,并将以二进制格式写入给定的数字。与stdout屏幕上的输出相同。

文件导航和I / O

还有其他几个课程,我们将要了解文件导航和I / O的基础知识。

Java目录

目录是可以包含其他文件和目录列表的文件。您可以使用File对象创建目录,列出目录中可用的文件。有关完整的详细信息,请查看可以调用File对象的所有方法的列表以及与目录相关的内容。

创建目录

有两个有用的文件实用程序方法可用于创建目录 -

以下示例创建“/ 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 - 异常

异常(或异常事件)是在执行程序期间出现的问题。异常发生时,程序的正常流程中断,程序/应用程序异常终止,这是不推荐的,因此,这些异常将被处理。

许多不同的原因可能会发生例外。以下是发生异常的情况。

这些异常中的一些是由用户错误引起的,其他的异常是由程序员错误引起的,而其他异常则是以某种方式失败的物理资源造成的。

基于这些,我们有三类异常。您需要了解它们以了解异常处理在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。

例如,如果您在程序中声明了大小为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)

异常层次结构

所有异常类都是java.lang.Exception类的子类型。异常类是Throwable类的一个子类。除了异常类之外,还有另一个称为Error的子类,它来自Throwable类。

错误是在严重故障的情况下发生的异常情况,这些情况不由Java程序处理。生成错误以指示运行时环境生成的错误。示例:JVM内存不足。通常,程序无法从错误中恢复。

Exception类有两个主要的子类:IOException类和RuntimeException类。

例外1

以下是最常见的已检查和未检查的Java的内置例外列表

异常方法

以下是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对象的堆栈跟踪,添加堆栈跟踪中的任何先前信息。

捕捉异常

一种方法使用trycatch关键字的组合捕获异常一个try / catch块放在可能会产生异常的代码周围。try / catch块中的代码被称为受保护代码,并且使用try / catch的语法如下所示:

用法

try {
   // Protected code
}catch(ExceptionName e1) {
   // Catch block
}

容易发生异常的代码放在try块中。发生异常时,发生的异常由与其关联的catch块处理。每个try块都应该被一个catch块或者最后一个块拦截。

catch语句涉及声明您尝试捕获的异常类型。如果受保护的代码发生异常,则会检查try之后的catch块(或块)。如果发生的异常类型列在catch块中,那么异常将传递给catch块,因为参数传递给一个method参数。

以下是使用2个元素声明的数组。然后代码试图访问3 ,其抛出异常数组的元件。

// 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关键字声明它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
}

最后的块

最后一个块遵循try块或catch块。最终的代码块总是执行,而不管Exception是否发生。

使用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

请注意以下几点:

试用资源

通常,当我们使用任何资源,如流,连接等,我们必须使用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();
         }
      }
   }
}

try-with-resources(也称为自动资源管理)是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();
      }
   }
}

在使用资源资源语句时,要牢记以下几点。

用户定义的异常

您可以在Java中创建自己的异常。在编写自己的异常类时,请记住以下几点:

我们可以定义我们自己的Exception类如下:

class MyException extends Exception {
}

您只需要扩展预定义的Exception类来创建自己的异常。这些被认为是检查异常。下面InsufficientFundsException类是扩展了异常类,使得它检查异常一个用户定义的异常。异常类就像任何其他类一样,包含有用的字段和方法。

// 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("
Withdrawing $100...");
         c.withdraw(100.00);
         System.out.println("
Withdrawing $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中,可以定义两个“异常和错误”。

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());
   }
}

如果您编译并执行上述程序,您将获得以下结果 -

输出

The value of num in the class Test is: 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

Java - 继承

继承可以定义为一个类获取另一个类的属性(方法和字段)的过程。通过使用继承,信息可以按层次顺序进行管理。

继承其他属性的类称为子类(派生类,子类),属性被继承的类称为超类(基类,父类)。

扩展关键字

extends是用于继承类的属性的关键字。以下是extends关键字的语法。

用法

class Super {
   .....
   .....
}
class Sub extends Super {
   .....
   .....
}

示例代码

以下是演示Java继承的示例。在这个例子中,你可以看到两个类,即Calculation和My_Calculation。

使用extends关键字,My_Calculation继承了Calculation类的方法addition()和Subtraction()。

将以下程序复制并粘贴到名称为My_Calculation.java的文件中

class Calculation {
   int z;
	
   public void addition(int x, int y) {
      z = x + y;
      System.out.println("The sum of the given numbers:"+z);
   }
	
   public void Subtraction(int x, int y) {
      z = x - y;
      System.out.println("The difference between the given numbers:"+z);
   }
}

public class My_Calculation extends Calculation {
   public void multiplication(int x, int y) {
      z = x * y;
      System.out.println("The product of the given numbers:"+z);
   }
	
   public static void main(String args[]) {
      int a = 20, b = 10;
      My_Calculation demo = new My_Calculation();
      demo.addition(a, b);
      demo.Subtraction(a, b);
      demo.multiplication(a, b);
   }
}

编译并执行上述代码,如下图所示。

javac My_Calculation.java
java My_Calculation

执行程序后,输出结果如下-

输出

The sum of the given numbers:30
The difference between the given numbers:10
The product of the given numbers:200

在给定的程序中,当创建一个对象到My_Calculation类时,会在其中创建一个类的内容副本。这就是为什么使用子类的对象可以访问超类的成员。

遗产

超类参考变量可以保存子类对象,但使用该变量只能访问超类的成员,因此要访问这两个类的成员,建议始终为子类创建引用变量。

如果你考虑上面的程序,你可以实例化下面给出的类。但是使用超类参考变量(在这种情况下为cal),您不能调用属于子类My_Calculation 的方法multiplier()

Calculation cal = new My_Calculation();
demo.addition(a, b);
demo.Subtraction(a, b);

- 子类从其超类继承所有成员(字段,方法和嵌套类)。构造函数不是成员,所以它们不被子类继承,但是可以从子类调用超类的构造函数。

超级关键字

超级关键字类似于关键字。以下是使用超级关键字的场景。

区分议员

如果一个类继承了另一个类的属性。如果超类的成员具有与子类相同的名称,为区分这些变量,我们使用super关键字,如下所示。

super.variable
super.method();

示例代码

本节提供了一个演示超级关键字的用法的程序

在给定的程序中,您有两个类,即Sub_classSuper_class,它们都有一个名为display()的不同实现的方法,另一个名为num的变量的值不同。我们正在调用这两个类的display()方法,并打印两个类的变量num的值。在这里,您可以观察到我们使用超级关键字来区分超类的成员与子类。

将程序复制并粘贴到名为Sub_class.java的文件中。

class Super_class {
   int num = 20;

   // display method of superclass
   public void display() {
      System.out.println("This is the display method of superclass");
   }
}

public class Sub_class extends Super_class {
   int num = 10;

   // display method of sub class
   public void display() {
      System.out.println("This is the display method of subclass");
   }

   public void my_method() {
      // Instantiating subclass
      Sub_class sub = new Sub_class();

      // Invoking the display() method of sub class
      sub.display();

      // Invoking the display() method of superclass
      super.display();

      // printing the value of variable num of subclass
      System.out.println("value of the variable named num in sub class:"+ sub.num);

      // printing the value of variable num of superclass
      System.out.println("value of the variable named num in super class:"+ super.num);
   }

   public static void main(String args[]) {
      Sub_class obj = new Sub_class();
      obj.my_method();
   }
}

使用以下语法编译并执行上述代码。

javac Super_Demo
java Super

执行该程序时,将得到以下结果 -

输出

This is the display method of subclass
This is the display method of superclass
value of the variable named num in sub class:10
value of the variable named num in super class:20

调用超类构造函数

如果一个类继承了另一个类的属性,则子类将自动获取超类的默认构造函数。但是如果要调用超类的参数化构造函数,则需要使用super关键字,如下所示。

super(values);

示例代码

本节中给出的程序演示了如何使用super关键字来调用超类的参数化构造函数。该程序包含一个超类和一个子类,其中超类包含接受字符string值的参数化构造函数,我们使用super关键字来调用超类的参数化构造函数。

将以下程序复制并粘贴到名称为Subclass.java的文件中

class Superclass {
   int age;

   Superclass(int age) {
      this.age = age; 		 
   }

   public void getAge() {
      System.out.println("The value of the variable named age in super class is: " +age);
   }
}

public class Subclass extends Superclass {
   Subclass(int age) {
      super(age);
   }

   public static void main(String argd[]) {
      Subclass s = new Subclass(24);
      s.getAge();
   }
}

使用以下语法编译并执行上述代码。

javac Subclass
java Subclass

执行该程序时,将得到以下结果 -

输出

The value of the variable named age in super class is: 24

IS-A关系

IS-A是一种说法:该对象是该对象的一种类型。让我们看看如何使用extends关键字来实现继承。

公共Animal { }   


公共Mammal extends Animal { }     


公共爬行扩展动物{ }     


公共延伸哺乳动物{ }     

现在,基于上面的例子,在面向对象的术语中,以下是真实的 -

现在,如果我们考虑IS-A的关系,我们可以说 -

通过使用extends关键字,子类将能够继承超类的所有属性,但超类的私有属性除外。

我们可以确保Mammal实际上是使用实例操作符的动物。

class Animal {
}

class Mammal extends Animal {
}

class Reptile extends Animal {
}

public class Dog extends Mammal {

   public static void main(String args[]) {
      Animal a = new Animal();
      Mammal m = new Mammal();
      Dog d = new Dog();

      System.out.println(m instanceof Animal);
      System.out.println(d instanceof Mammal);
      System.out.println(d instanceof Animal);
   }
}

输出结果如下 -

输出

true
true
true

因为我们有一个很好的理解延伸的关键字,让我们看看到如何农具关键字用于获取IS-A的关系。

通常,implements关键字与类一起使用以继承接口的属性。接口不能被类扩展。

public interface Animal {
}

public class Mammal implements Animal {
}

public class Dog extends Mammal {
}

关键字的instanceof

让我们使用instanceof运算符来确定Mammal是否实际上是Animal,而Dog实际上是Animal。

interface Animal{}
class Mammal implements Animal{}

public class Dog extends Mammal {

   public static void main(String args[]) {
      Mammal m = new Mammal();
      Dog d = new Dog();

      System.out.println(m instanceof Animal);
      System.out.println(d instanceof Mammal);
      System.out.println(d instanceof Animal);
   }
}

输出结果如下 -

输出

true
true
true

HAS-A关系

这些关系主要是基于使用。这决定某一类HAS-A是否确定。这种关系有助于减少代码的重复以及错误。

让我们来看一个例子 -

public class Vehicle{}
public class Speed{}

public class Van extends Vehicle {
   private Speed sp;
} 

这表明Van HAS-A速度。通过为Speed分开一个类,我们不必将Van class中的所有速度归入速度,这样可以在多个应用程序中重用Speed类。

在面向对象的功能中,用户不必担心哪个对象正在做真正的工作。为了实现这一点,Van类隐藏了Van类的用户的实现细节。所以,基本上发生的是用户会要求Van类做一些动作,Van Class会自己做这个工作,或者让另一个类执行这个动作。

继承类型

有各种类型的继承,如下所示。

继承类型

要记住的一个非常重要的事实是Java不支持多重继承。这意味着一个类不能扩展多个类。因此以下是非法的 -

public class extends Animal, Mammal{} 

然而,一个类可以实现一个或多个接口,这有助于Java摆脱不可能的多重继承。

Java - 覆盖

在上一章中,我们探讨了超类和子类。如果一个类从其超类继承一个方法,那么有一个机会可以覆盖该方法,只要它不被标记为final。

覆盖的好处是:能够定义特定于子类型的行为,这意味着一个子类可以根据其需求实现父类方法。

在面向对象的术语中,覆盖方法是覆盖现有方法的功能。

我们来看一个例子。

class Animal {
   public void move() {
      System.out.println("Animals can move");
   }
}

class Dog extends Animal {
   public void move() {
      System.out.println("Dogs can walk and run");
   }
}

public class TestDog {

   public static void main(String args[]) {
      Animal a = new Animal();   // Animal reference and object
      Animal b = new Dog();   // Animal reference but Dog object

      a.move();   // runs the method in Animal class
      b.move();   // runs the method in Dog class
   }
}

输出结果如下 -

输出

Animals can move
Dogs can walk and run

在上面的例子中,您可以看到即使b是Animal类型,它也会在Dog类中运行move方法。其原因是:在编译时,对引用类型进行检查。但是,在运行时,JVM计算出对象类型,并运行属于该特定对象的方法。

因此,在上面的例子中,由于Animal类具有方法移动,程序将正确编译。然后,在运行时,它运行该对象特有的方法。

考虑以下示例 -

class Animal {
   public void move() {
      System.out.println("Animals can move");
   }
}

class Dog extends Animal {
   public void move() {
      System.out.println("Dogs can walk and run");
   }
   public void bark() {
      System.out.println("Dogs can bark");
   }
}

public class TestDog {

   public static void main(String args[]) {
      Animal a = new Animal();   // Animal reference and object
      Animal b = new Dog();   // Animal reference but Dog object

      a.move();   // runs the method in Animal class
      b.move();   // runs the method in Dog class
      b.bark();
   }
}

输出结果如下 -

输出

TestDog.java:26: error: cannot find symbol
      b.bark();
       ^
  symbol:   method bark()
  location: variable b of type Animal
1 error

这个程序会抛出一个编译时错误,因为b的引用类型Animal没有一个名称为bark的方法。

方法覆盖规则

使用超级关键字

当调用类方法时,使用super关键字。

class Animal {
   public void move() {
      System.out.println("Animals can move");
   }
}

class Dog extends Animal {
   public void move() {
      super.move();   // invokes the super class method
      System.out.println("Dogs can walk and run");
   }
}

public class TestDog {

   public static void main(String args[]) {
      Animal b = new Dog();   // Animal reference but Dog object
      b.move();   // runs the method in Dog class
   }
}

输出结果如下 -

输出

Animals can move
Dogs can walk and run

Java - 多态

多态性是对象承担许多形式的能力。当使用父类引用引用子类对象时,OOP中最常见的多态使用会发生。

任何可以通过多个IS-A测试的Java对象被认为是多态的。在Java中,所有Java对象都是多态的,因为任何对象都将通过IS-A测试来为自己的类型和类Object传递。

重要的是要知道访问对象的唯一可能方式是通过引用变量。参考变量只能是一种类型。一旦声明,引用变量的类型就无法更改。

引用变量可以重新分配给其他对象,只要它不被声明为final。引用变量的类型将确定它可以在对象上调用的方法。

引用变量可以引用其声明类型的任何对象或其声明类型的任何子类型。引用变量可以声明为类或接口类型。

我们来看一个例子。

public interface Vegetarian{}
public class Animal{}
public class Deer extends Animal implements Vegetarian{}

现在,Deer类被认为是多态的,因为它具有多重继承。以下是上面的例子 -

当我们将参考变量事实应用于Deer对象引用时,以下声明是合法的 -

Deer d = new Deer();
Animal a = d;
Vegetarian v = d;
Object o = d;

所有参考变量d,a,v,o指的是堆中相同的Deer对象。

虚拟方法

在本节中,我将向您展示如何在Java中重写方法的行为允许您在设计类时利用多态。

我们已经探讨了覆盖方法,其中子类可以覆盖其父类中的方法。一个被覆盖的方法基本上隐藏在父类中,除非子类在重写方法中使用super关键字,否则不被调用。

/* File name : Employee.java */
public class Employee {
   private String name;
   private String address;
   private int number;

   public Employee(String name, String address, int number) {
      System.out.println("Constructing an Employee");
      this.name = name;
      this.address = address;
      this.number = number;
   }

   public void mailCheck() {
      System.out.println("Mailing a check to " + this.name + " " + this.address);
   }

   public String toString() {
      return name + " " + address + " " + number;
   }

   public String getName() {
      return name;
   }

   public String getAddress() {
      return address;
   }

   public void setAddress(String newAddress) {
      address = newAddress;
   }

   public int getNumber() {
      return number;
   }
}

现在假设我们扩展Employee类如下 -

/* File name : Salary.java */
public class Salary extends Employee {
   private double salary; // Annual salary
   
   public Salary(String name, String address, int number, double salary) {
      super(name, address, number);
      setSalary(salary);
   }
   
   public void mailCheck() {
      System.out.println("Within mailCheck of Salary class ");
      System.out.println("Mailing check to " + getName()
      + " with salary " + salary);
   }
   
   public double getSalary() {
      return salary;
   }
   
   public void setSalary(double newSalary) {
      if(newSalary >= 0.0) {
         salary = newSalary;
      }
   }
   
   public double computePay() {
      System.out.println("Computing salary pay for " + getName());
      return salary/52;
   }
}

现在,您仔细研究以下程序,并尝试确定其输出 -

/* File name : VirtualDemo.java */
public class VirtualDemo {

   public static void main(String [] args) {
      Salary s = new Salary("Mohd Mohtashim", "Ambehta, UP", 3, 3600.00);
      Employee e = new Salary("John Adams", "Boston, MA", 2, 2400.00);
      System.out.println("Call mailCheck using Salary reference --");   
      s.mailCheck();
      System.out.println("
 Call mailCheck using Employee reference--");
      e.mailCheck();
   }
}

输出结果如下 -

输出

Constructing an Employee
Constructing an Employee

Call mailCheck using Salary reference --
Within mailCheck of Salary class
ailing check to Mohd Mohtashim with salary 3600.0

Call mailCheck using Employee reference--
Within mailCheck of Salary class
ailing check to John Adams with salary 2400.0

在这里,我们实例化两个薪水对象。一个使用工资参考小号,另一个使用一个雇员参考"e

在调用s.mailCheck()时,编译器在编译时看到Salary类中的mailCheck(),并且JVM在运行时调用Salary类中的mailCheck()。

e上的mailCheck()是非常不同的,因为e是一个Employee参考。当编译器看到e.mailCheck()时,编译器会在Employee类中看到mailCheck()方法。

在编译时,编译器使用Employee中的mailCheck()验证此语句。但是,在运行时,JVM在Salary类中调用mailCheck()。

这种行为被称为虚拟方法调用,这些方法称为虚拟方法。在运行时调用重写的方法,无论在编译时使用源代码中的引用是什么数据类型。

Java - 抽象

根据字典,抽象是处理想法而不是事件的质量。例如,当您考虑电子邮件的情况时,复杂的详细信息(如发送电子邮件时会发生什么),您的电子邮件服务器使用的协议将从用户隐藏。因此,要发送一封电子邮件,您只需要输入内容,提及接收方的地址,然后单击发送。

同样在面向对象编程中,抽象是从用户隐藏实现细节的过程,只有功能将被提供给用户。换句话说,用户将具有关于对象所做的内容的信息,而不是使用它。

在Java中,抽象是使用抽象类和接口实现的。

抽象班

在其声明中包含抽象关键字的类称为抽象类。

本节为您提供抽象类的示例。要创建一个抽象类,只需在class关键字之前的类声明中使用abstract关键字。

/* File name : Employee.java */
public abstract class Employee {
   private String name;
   private String address;
   private int number;

   public Employee(String name, String address, int number) {
      System.out.println("Constructing an Employee");
      this.name = name;
      this.address = address;
      this.number = number;
   }
   
   public double computePay() {
     System.out.println("Inside Employee computePay");
     return 0.0;
   }
   
   public void mailCheck() {
      System.out.println("Mailing a check to " + this.name + " " + this.address);
   }

   public String toString() {
      return name + " " + address + " " + number;
   }

   public String getName() {
      return name;
   }
 
   public String getAddress() {
      return address;
   }
   
   public void setAddress(String newAddress) {
      address = newAddress;
   }
 
   public int getNumber() {
      return number;
   }
}

您可以观察到,除了抽象方法,Employee类与Java中的普通类相同。该类现在是抽象的,但它仍然有三个字段,七个方法和一个构造函数。

现在您可以尝试以下列方式实例化Employee类:

/* File name : AbstractDemo.java */
public class AbstractDemo {

   public static void main(String [] args) {
      /* Following is not allowed and would raise error */
      Employee e = new Employee("George W.", "Houston, TX", 43);
      System.out.println("
 Call mailCheck using Employee reference--");
      e.mailCheck();
   }
}

当你编译上面的类,它会给你以下错误 -

Employee.java:46: Employee is abstract; cannot be instantiated
      Employee e = new Employee("George W.", "Houston, TX", 43);
                   ^
1 error

继承抽象类

我们可以通过以下方式继承Employee类的属性:

/* File name : Salary.java */
public class Salary extends Employee {
   private double salary;   // Annual salary
   
   public Salary(String name, String address, int number, double salary) {
      super(name, address, number);
      setSalary(salary);
   }
   
   public void mailCheck() {
      System.out.println("Within mailCheck of Salary class ");
      System.out.println("Mailing check to " + getName() + " with salary " + salary);
   }
 
   public double getSalary() {
      return salary;
   }
   
   public void setSalary(double newSalary) {
      if(newSalary >= 0.0) {
         salary = newSalary;
      }
   }
   
   public double computePay() {
      System.out.println("Computing salary pay for " + getName());
      return salary/52;
   }
}

在这里,您不能实例化Employee类,但您可以实例化工资类,并使用此实例,您可以访问Employee类的所有三个字段和七个方法,如下所示。

/* File name : AbstractDemo.java */
public class AbstractDemo {

   public static void main(String [] args) {
      Salary s = new Salary("Mohd Mohtashim", "Ambehta, UP", 3, 3600.00);
      Employee e = new Salary("John Adams", "Boston, MA", 2, 2400.00);
      System.out.println("Call mailCheck using Salary reference --");
      s.mailCheck();
      System.out.println("
 Call mailCheck using Employee reference--");
      e.mailCheck();
   }
}

这产生以下结果 -

输出

Constructing an Employee
Constructing an Employee
Call mailCheck using Salary reference --
Within mailCheck of Salary class 
Mailing check to Mohd Mohtashim with salary 3600.0

 Call mailCheck using Employee reference--
Within mailCheck of Salary class 
Mailing check to John Adams with salary 2400.0

抽象方法

如果您希望一个类包含一个特定的方法,但是希望该方法的实际实现由子类确定,则可以将父类中的方法声明为抽象。

以下是抽象方法的一个例子。

public abstract class Employee {
   private String name;
   private String address;
   private int number;
   
   public abstract double computePay();
   // Remainder of class definition
}

将方法声明为抽象有两个后果 -

- 最后一个后代类必须实现抽象方法; 否则,您将具有无法实例化的抽象类的层次结构。

假设Salary类继承Employee类,那么它应该实现computePay()方法,如下所示:

/* File name : Salary.java */
public class Salary extends Employee {
   private double salary;   // Annual salary
  
   public double computePay() {
      System.out.println("Computing salary pay for " + getName());
      return salary/52;
   }
   // Remainder of class definition
}

Java - 封装

封装是四个基本的OOP概念之一。另外三个是继承,多态和抽象。

Java中的封装是将数据(变量)和作为数据(方法)的代码作为一个单元进行包装的机制。在封装中,类的变量将从其他类隐藏,只能通过其当前类的方法进行访问。因此,它也被称为数据隐藏

在Java中实现封装 -

以下是演示如何在Java中实现封装的示例 -

/* File name : EncapTest.java */
public class EncapTest {
   private String name;
   private String idNum;
   private int age;

   public int getAge() {
      return age;
   }

   public String getName() {
      return name;
   }

   public String getIdNum() {
      return idNum;
   }

   public void setAge( int newAge) {
      age = newAge;
   }

   public void setName(String newName) {
      name = newName;
   }

   public void setIdNum( String newId) {
      idNum = newId;
   }
}

公共setXXX()和getXXX()方法是EncapTest类的实例变量的访问点。通常,这些方法被称为getter和setter。因此,任何想要访问变量的类都可以通过这些getter和setter访问它们。

可以使用以下程序访问EncapTest类的变量 -

/* File name : RunEncap.java */
public class RunEncap {

   public static void main(String args[]) {
      EncapTest encap = new EncapTest();
      encap.setName("James");
      encap.setAge(20);
      encap.setIdNum("12343ms");

      System.out.print("Name : " + encap.getName() + " Age : " + encap.getAge());
   }
}

输出结果如下 -

输出

Name : James Age : 20

封装的好处

Java - 接口

接口是Java中的引用类型。它类似于类。它是抽象方法的集合。一个类实现一个接口,从而继承接口的抽象方法。

除了抽象方法之外,接口还可以包含常量,默认方法,静态方法和嵌套类型。方法体只存在于默认方法和静态方法。

编写界面类似于编写类。但是一个类描述了一个对象的属性和行为。一个接口包含类实现的行为。

除非实现接口的类是抽象的,否则接口的所有方法都需要在类中定义。

接口类似于以下几种类:

然而,一个接口与几个方面不同,包括 -

声明接口

接口关键字用于声明的接口。这是一个简单的例子来声明一个接口 -

以下是一个接口的例子 -

/* File name : NameOfInterface.java */
import java.lang.*;
// Any number of import statements

public interface NameOfInterface {
   // Any number of final, static fields
   // Any number of abstract method declarations
}

接口具有以下属性 -

/* File name : Animal.java */
interface Animal {
   public void eat();
   public void travel();
}

实现接口

当一个类实现一个接口时,你可以将类认为是签约,同意执行接口的具体行为。如果类不执行接口的所有行为,则类必须声明为抽象。

一个类使用implements关键字实现一个接口。implements关键字出现在声明的扩展部分之后的类声明中。

/* File name : MammalInt.java */
public class MammalInt implements Animal {

   public void eat() {
      System.out.println("Mammal eats");
   }

   public void travel() {
      System.out.println("Mammal travels");
   } 

   public int noOfLegs() {
      return 0;
   }

   public static void main(String args[]) {
      MammalInt m = new MammalInt();
      m.eat();
      m.travel();
   }
} 

输出结果如下 -

输出

Mammal eats
Mammal travels

当覆盖接口中定义的方法时,有几个规则要遵循 -

当实现接口时,有几个规则 -

扩展接口

接口可以以类扩展另一个类的方式扩展另一个接口。所述延伸关键字用于扩展接口,而子接口继承父接口的方法。

以下运动界面由曲棍球和足球界面扩展。

// Filename: Sports.java
public interface Sports {
   public void setHomeTeam(String name);
   public void setVisitingTeam(String name);
}

// Filename: Football.java
public interface Football extends Sports {
   public void homeTeamScored(int points);
   public void visitingTeamScored(int points);
   public void endOfQuarter(int quarter);
}

// Filename: Hockey.java
public interface Hockey extends Sports {
   public void homeGoalScored();
   public void visitingGoalScored();
   public void endOfPeriod(int period);
   public void overtimePeriod(int ot);
}

曲棍球界面有四种方法,但它从运动中继承了两种方法。因此,实施曲棍球的课程需要实现所有六种方法。同样,实现足球的课程需要从“足球”和“体育”两种方法中定义三种方法。

扩展多个接口

Java类只能扩展一个父类。不允许多重继承。接口不是类,而接口可以扩展多个父接口。

extend关键字使用一次,父接口以逗号分隔的列表声明。

例如,如果曲棍球界面扩展了运动和事件,它将被声明为 -

public interface Hockey extends Sports, Event

标记接口

当父界面不包含任何方法时,扩展接口的最常见用途就是发生。例如,java.awt.event包中的MouseListener接口扩展java.util.EventListener,它被定义为 -

package java.util;
public interface EventListener
{}

其中没有方法的接口被称为标记接口。标记界面有两个基本的设计目的 -

创建一个公共父 - 与通过Java API中的数十个其他接口扩展的EventListener接口一样,您可以使用标记接口在一组接口中创建公共父级。例如,当接口扩展了EventListener时,JVM知道这个特定的接口将被用于事件委托方案。

向类添加数据类型 - 这种情况是标记来自哪里。实现标记接口的类不需要定义任何方法(因为接口没有),而是通过多态来形成接口类型。

Java - 软件包

软件包用于Java,以防止命名冲突,控制访问,使查找/定位和使用类,接口,枚举和注释更容易等。

一个可以被定义为相关类型(类,接口,枚举和注解)提供访问保护和命名空间管理的分组。

Java中的一些现有软件包是 -

程序员可以定义自己的软件包来捆绑一组类/接口等。对于由你实现的相关类进行分组是一个很好的做法,程序员可以很容易地确定类,接口,枚举和注释是相关的。

由于包创建一个新的命名空间,所以与其他包中的名称不会有任何名称冲突。使用包,更容易提供访问控制,并且更容易找到相关的类。

创建包

在创建软件包时,您应该为软件包选择一个名称,并在包含要包含在软件包中的类,接口,枚举和注释类型的每个源文件的顶部包含一个语句以及该名称。

软件包语句应该是源文件中的第一行。每个源文件中只能有一个package语句,它适用于文件中的所有类型。

如果不使用package语句,则类,接口,枚举和注释类型将被放置在当前的默认包中。

要使用package语句编译Java程序,必须使用-d选项,如下所示。

javac -d Destination_folder file_name.java

然后在指定的目标中创建具有给定包名称的文件夹,并将编译的类文件放在该文件夹中。

我们来看一个创建一个名为animals的包的例子使用小写字母的包名称避免与类和接口的名称发生冲突是一个很好的做法。

以下包示例包含接口命名动物 -

/* File name : Animal.java */
package animals;

interface Animal {
   public void eat();
   public void travel();
}

现在,让我们在同一个包中实现上述界面动物 -

package animals;
/* File name : MammalInt.java */

public class MammalInt implements Animal {

   public void eat() {
      System.out.println("Mammal eats");
   }

   public void travel() {
      System.out.println("Mammal travels");
   } 

   public int noOfLegs() {
      return 0;
   }

   public static void main(String args[]) {
      MammalInt m = new MammalInt();
      m.eat();
      m.travel();
   }
} 

现在编译java文件如下图所示:

$ javac -d . Animal.java 
$ javac -d . MammalInt.java

现在,将在当前目录中创建一个名为animals的包/文件夹,这些类文件将被放在其中,如下所示。

包装

您可以在程序包中执行类文件,并获得如下所示的结果。

Mammal eats
Mammal travels

导入关键字

如果一个类想在同一个包中使用另一个类,则不需要使用包名称。同一个包中的类找不到任何特殊语法。

在这里,一个名为Boss的类被添加到已经包含Employee的工资单包中。然后,Boss可以引用Employee类,而不使用工资核算前缀,如以下Boss类所示。

package payroll;
public class Boss {
   public void payEmployee(Employee e) {
      e.mailCheck();
   }
}

如果员工类不在工资单中,会发生什么?Boss类必须使用以下技术之一来引用不同包中的类。

payroll.Employee
import payroll.*;
import payroll.Employee;

- 类文件可以包含任意数量的导入语句。import语句必须出现在package语句之后和类声明之前。

包的目录结构

当一个类放在一个包中时,会发生两个主要的结果 -

以下是使用Java管理文件的简单方法 -

将类,接口,枚举或注释类型的源代码放在一个文本文件中,其名称是类型的简单名称,扩展名为.java

例如 -

// File Name :  Car.java
package vehicle;

public class Car {
   // Class implementation.   
}

现在,将源文件放在名称反映该类所属的包的名称的目录中 -

....vehicleCar.java

现在,合格的类名和路径名如下 -

一般来说,公司使用其反向互联网域名作为其包名。

示例 - 公司的互联网域名是apple.com,那么所有的包名都将以com.apple开头。包名称的每个组件对应于一个子目录。

示例 - 该公司有一个包含Dell.java源文件的com.apple.computers包,它将包含在一系列这样的子目录中 -

....comapplecomputersDell.java

在编译时,编译器为其中定义的每个类,接口和枚举创建不同的输出文件。输出文件的基本名称是类型的名称,其扩展名为.class

例如 -

// File Name: Dell.java
package com.apple.computers;

public class Dell {
}

class Ups {
}

现在,使用-d选项编译此文件如下:

$javac -d . Dell.java

这些文件将被编译如下 -

.comapplecomputersDell.class
.comapplecomputersUps.class

您可以导入 com apple computers 定义的所有类或接口,如下所示:

import com.apple.computers.*;

与.java源文件一样,编译的.class文件应该在一系列反映程序包名称的目录中。但是,.class文件的路径不一定与.java源文件的路径相同。您可以分别安排您的源代码和类目录,如

<path-one>sourcescomapplecomputersDell.java

<path-two>classescomapplecomputersDell.class

通过这样做,可以将classes目录访问给其他程序员,而不会泄露您的来源。您还需要以这种方式管理源文件和类文件,以便编译器和Java虚拟机(JVM)可以找到程序使用的所有类型。

类目录<path-two> classes的完整路径称为类路径,并且使用CLASSPATH系统变量进行设置。编译器和JVM都可以通过将包名添加到类路径来创建.class文件的路径。

说<path-two> classes是类路径,包名是com.apple.computers,那么编译器和JVM将在<path-two> classes com apple computers中查找.class文件。

类路径可以包括几个路径。多个路径应以分号(Windows)或冒号(Unix)分隔。默认情况下,编译器和JVM搜索当前目录和包含Java平台类的JAR文件,以便这些目录自动位于类路径中。

设置CLASSPATH系统变量

要显示当前的CLASSPATH变量,请在Windows和UNIX(Bourne shell)中使用以下命令 -

要删除CLASSPATH变量的当前内容,请使用 -

要设置CLASSPATH变量 -

Java - 数据结构

Java实用程序包提供的数据结构非常强大,执行范围广泛的功能。这些数据结构由以下接口和类组成 -

所有这些类现在都是传统的,而Java-2引入了一个名为Collections Framework的新框架,这将在下一章中探讨。 -

枚举

枚举界面本身不是数据结构,但在其他数据结构的上下文中非常重要。枚举界面定义了一种从数据结构中检索连续元素的方法。

例如,枚举定义了一个名为nextElement的方法,用于获取包含多个元素的数据结构中的下一个元素。

要了解有关此界面的更多详细信息,请选中枚举

BitSet

BitSet类实现了可以单独设置和清除的一组位或标志。

在你需要跟上一组布尔值的情况下,这个类是非常有用的; 您只需为每个值分配一点,并根据需要进行设置或清除。

有关此类的更多详细信息,请查看BitSet

矢量

Vector类与传统的Java数组类似,除了它可以根据需要增长以适应新元素。

像数组一样,Vector对象的元素可以通过向量中的索引来访问。

使用Vector类的好处在于,您不必担心在创建时将其设置为特定大小; 它在需要时自动收缩并增长。

有关此类的更多详细信息,请选择“矢量”

堆栈

Stack类实现了先进先出(LIFO)的元素堆栈。

您可以将堆栈字面意思上看作垂直堆叠的对象; 当你添加一个新的元素,它被堆叠在其他元素之上。

当您将一个元素从堆栈中拉出时,它从顶部脱落。换句话说,你添加到堆栈的最后一个元素是第一个要重新启动的元素。

有关此类的更多详细信息,请检查堆栈

词典

Dictionary类是一个抽象类,它定义了将键映射到值的数据结构。

这在您希望能够通过特定键而不是整数索引访问数据的情况下很有用。

由于Dictionary类是抽象的,它只提供了关键映射数据结构的框架,而不是特定的实现。

有关此类的更多详细信息,请选择“字典”

哈希表

Hashtable类提供了一种基于一些用户定义的键结构来组织数据的方法。

例如,在地址列表哈希表中,您可以根据邮政编码而不是某个人的名称来存储和排序数据。

关于哈希表的密钥的具体含义完全取决于哈希表及其包含的数据的使用。

有关此类的更多详细信息,请查看Hashtable

属性

属性是Hashtable的子类。它用于维护键的列表,其中的键是一个String,该值也是一个String。

Properties类被许多其他Java类使用。例如,它是获取环境值时由System.getProperties()返回的对象的类型。

有关此类的更多详细信息,请选择“属性”

Java - 集合框架

在Java 2之前,Java提供了诸如字典,向量,堆栈属性之类的ad hoc类来存储和操作对象组。虽然这些课程很有用,但却缺乏中心统一的主题。因此,您使用Vector的方式与使用“属性”的方式不同。

收藏框架旨在实现几个目标,如 -

为此,整个集合框架围绕一组标准接口进行设计。提供了这些接口的几个标准实现(如LinkedList,HashSetTreeSet),您可以按原样使用,如果选择,您还可以实现自己的集合。

集合框架是用于表示和操作集合的统一架构。所有集合框架包含以下内容 -

除了集合之外,框架还定义了几个映射接口和类。地图存储键/值对。虽然地图是不是收藏在正确使用的术语,但它们与收藏完全集成。

收藏界面

集合框架定义了几个接口。本节提供每个界面的概述 -

没有 接口和说明
1 集合界面

这使您能够处理对象组; 它位于集合层次结构的顶部。

2 列表界面

这扩展了Collection,List的一个实例存储有序的元素集合。

3 集合

这扩展了集合来处理集合,它必须包含唯一的元素。

4 SortedSet

这扩展了Set来处理排序集。

5 地图

这将唯一键映射到值。

6 Map.Entry

这描述了地图中的元素(键/值对)。这是Map的内部类。

7 SortedMap

这扩展了Map,以便按照升序保持密钥。

8 枚举

这是传统界面定义了可以枚举(一次获取一个)对象集合中的元素的方法。这个传统界面已被Iterator所取代。

集合类

Java提供了一组实现Collection接口的标准集合类。一些类提供可以按原样使用的完整实现,而其他类是抽象类,提供用作创建具体集合的起点的骨架实现。

标准收集类汇总在下表中 -

没有 Class及说明
1

摘要

实现大部分的Collection界面。

2

抽象列表

扩展AbstractCollection并实现大多数List接口。

3

AbstractSequentialList

扩展AbstractList供集合使用,该集合使用其元素的顺序而不是随机访问。

4 LinkedList

通过扩展AbstractSequentialList来实现链表。

5 ArrayList

通过扩展AbstractList来实现动态数组。

6

抽象集

扩展AbstractCollection并实现大多数Set接口。

7 哈希集

扩展AbstractSet用于哈希表。

8 LinkedHashSet

扩展HashSet以允许插入顺序迭代。

9 树集

实现一个存储在树中的集合。扩展AbstractSet。

10

抽象图

实现大多数Map界面。

11 HashMap

扩展AbstractMap以使用哈希表。

12 TreeMap

扩展AbstractMap以使用树。

13 WeakHashMap

扩展AbstractMap以使用带有弱键的哈希表。

14 LinkedHashMap

扩展HashMap以允许插入顺序迭代。

15 IdentityHashMap

扩展AbstractMap并在比较文档时使用参考等同。

类AbstractCollection,AbstractSet,AbstractList中,AbstractSequentialListAbstractMap类提供核心集合接口的骨干实现,以最小化来实现他们所需要的努力。

在上一章中探讨了由java.util定义的以下遗留类 -

没有 Class及说明
1 向量

这实现了一个动态数组。它类似于ArrayList,但有一些差异。

2 堆栈

Stack是Vector的一个子类,它实现了一个标准的先进先出的堆栈。

3 字典

字典是一个抽象类,表示一个键/值存储库,操作非常像Map。

4 哈希表

Hashtable是原始java.util的一部分,是Dictionary的具体实现。

5 属性

属性是Hashtable的子类。它用于维护键的列表,其中的键是一个String,该值也是一个String。

6 BitSet

BitSet类创建一个特殊类型的数组,它保存位值。这个数组可以根据需要增加大小。

集合算法

集合框架定义了可应用于集合和映射的几种算法。这些算法被定义为Collections类中的静态方法。

有几个方法可以抛出一个ClassCastException异常,当试图比较不兼容的类型,或发生UnsupportedOperationException异常,当试图修改一个不可修改的集合发生。

集合定义了三个静态变量:EMPTY_SET,EMPTY_LIST和EMPTY_MAP。都是不变的

没有 算法和描述
1 集合算法

以下是所有算法实现的列表。

如何使用迭代器?

通常,您将想要循环遍历集合中的元素。例如,您可能希望显示每个元素。

最简单的方法是使用迭代器,它是一个实现Iterator或ListIterator接口的对象。

迭代器使您能够遍历集合,获取或删除元素。ListIterator扩展了Iterator以允许双向遍历列表和修改元素。

没有 迭代器方法和描述
1 使用Java Iterator

以下是Iterator和ListIterator接口提供的示例的所有方法的列表。

如何使用比较器?

TreeSet和TreeMap都以排序顺序存储元素。但是,比较器是正确定义排序顺序的意思。

这个界面让我们可以使用不同的方式对给定的集合进行排序。此接口也可用于对任何类的任何实例进行排序(甚至我们无法修改的类)。

没有 迭代器方法和描述
1 使用Java比较器

以下是比较器接口提供的示例的所有方法的列表。

概要

Java集合框架使程序员能够访问预先封装的数据结构以及操作它们的算法。

集合是可以保存对其他对象的引用的对象。集合接口声明可以对每种类型的集合执行的操作。

集合框架的类和接口在包java.util中。

Java - 泛型

如果我们可以编写一个排序方法,可以对Integer数组,String数组或支持排序的任何类型的数组进行排序,那将是很好的。

Java 泛型方法和通用类使程序员能够使用单个方法声明分别指定一组相关方法,或者使用单个类声明来指定一组相关类型。

泛型还提供编译时类型的安全性,允许程序员在编译时捕获无效类型。

使用Java Generic概念,我们可以编写一个用于排序对象数组的通用方法,然后使用Integer数组,Double数组,String数组等调用泛型方法来对数组元素进行排序。

通用方法

您可以编写一个可以使用不同类型的参数调用的泛型方法声明。根据传递给通用方法的参数的类型,编译器会适当地处理每个方法调用。以下是定义通用方法的规则 -

以下示例说明了如何使用单一的Generic方法打印不同类型的数组 -

public class GenericMethodTest {
   // generic method printArray
   public static < E > void printArray( E[] inputArray ) {
      // Display array elements
      for(E element : inputArray) {
         System.out.printf("%s ", element);
      }
      System.out.println();
   }

   public static void main(String args[]) {
      // Create arrays of Integer, Double and Character
      Integer[] intArray = { 1, 2, 3, 4, 5 };
      Double[] doubleArray = { 1.1, 2.2, 3.3, 4.4 };
      Character[] charArray = { "H", "E", "L", "L", "O" };

      System.out.println("Array integerArray contains:");
      printArray(intArray);   // pass an Integer array

      System.out.println("
Array doubleArray contains:");
      printArray(doubleArray);   // pass a Double array

      System.out.println("
Array characterArray contains:");
      printArray(charArray);   // pass a Character array
   }
}

输出结果如下 -

输出

Array integerArray contains:
1 2 3 4 5 

Array doubleArray contains:
1.1 2.2 3.3 4.4 

Array characterArray contains:
H E L L O

有界类型参数

有时候您可能希望限制允许传递给类型参数的类型。例如,对数字进行操作的方法可能只希望接受Number或其子类的实例。这是有界类型参数。

要声明一个有界类型的参数,列出type参数的名称,后跟extend关键字,然后是其上限。

以下示例说明如何在一般意义上使用扩展来表示“扩展”(如在类中)或“实现”(如在接口中)。这个例子是Generic方法返回最大的三个Comparable对象 -

public class MaximumTest {
   // determines the largest of three Comparable objects
   
   public static <T extends Comparable<T>> T maximum(T x, T y, T z) {
      T max = x;   // assume x is initially the largest
      
      if(y.compareTo(max) > 0) {
         max = y;   // y is the largest so far
      }
      
      if(z.compareTo(max) > 0) {
         max = z;   // z is the largest now                 
      }
      return max;   // returns the largest object   
   }
   
   public static void main(String args[]) {
      System.out.printf("Max of %d, %d and %d is %d

", 
         3, 4, 5, maximum( 3, 4, 5 ));

      System.out.printf("Max of %.1f,%.1f and %.1f is %.1f

",
         6.6, 8.8, 7.7, maximum( 6.6, 8.8, 7.7 ));

      System.out.printf("Max of %s, %s and %s is %s
","pear",
         "apple", "orange", maximum("pear", "apple", "orange"));
   }
}

输出结果如下 -

输出

Max of 3, 4 and 5 is 5

Max of 6.6,8.8 and 7.7 is 8.8

Max of pear, apple and orange is pear

通用类

通用类声明看起来像一个非泛型类声明,除了类名后跟一个类型参数部分。

与通用方法一样,泛型类的类型参数部分可以有一个或多个类型参数,用逗号分隔。这些类被称为参数化类或参数化类型,因为它们接受一个或多个参数。

下面的例子说明了我们如何定义一个泛型类 -

public class Box<T> {
   private T t;

   public void add(T t) {
      this.t = t;
   }

   public T get() {
      return t;
   }

   public static void main(String[] args) {
      Box<Integer> integerBox = new Box<Integer>();
      Box<String> stringBox = new Box<String>();
    
      integerBox.add(new Integer(10));
      stringBox.add(new String("Hello World"));

      System.out.printf("Integer Value :%d

", integerBox.get());
      System.out.printf("String Value :%s
", stringBox.get());
   }
}

输出结果如下 -

输出

Integer Value :10
String Value :Hello World

Java - 序列化

Java提供了一种称为对象序列化的机制,其中对象可以表示为包含对象数据的字节序列,以及有关对象的类型和存储在对象中的数据类型的信息。

将序列化对象写入文件后,可从文件中读取并反序列化,表示对象的类型信息和字节及其数据可用于重新创建内存中的对象。

最令人印象深刻的是,整个过程与JVM无关,意味着一个对象可以在一个平台上序列化,并且在完全不同的平台上反序列化。

ObjectInputStreamObjectOutputStream是包含用于序列化和反序列化对象的方法的高级流。

ObjectOutputStream类包含许多用于编写各种数据类型的写入方法,但是一种方法尤其突出 -

public final void writeObject(Object x) throws IOException

上述方法序列化一个对象并将其发送到输出流。类似地,ObjectInputStream类包含以下反序列化对象的方法 -

public final Object readObject() throws IOException, ClassNotFoundException

此方法从流中检索下一个Object,并将其反序列化。返回值为Object,因此您需要将其转换为适当的数据类型。

为了演示序列化在Java中的工作原理,我将使用我们早期探讨的Employee类。假设我们有以下Employee类,它实现了Serializable接口 -

public class Employee implements java.io.Serializable {
   public String name;
   public String address;
   public transient int SSN;
   public int number;
   
   public void mailCheck() {
      System.out.println("Mailing a check to " + name + " " + address);
   }
}

请注意,为了顺序化成功,必须满足两个条件 -

如果您好奇知道Java Standard Class是否可序列化,请检查该类的文档。测试很简单:如果类实现java.io.Serializable,那么它是可序列化的; 否则,不是。

序列化对象

ObjectOutputStream类用于序列化对象。以下SerializeDemo程序实例化一个Employee对象并将其序列化到一个文件。

执行完程序后,将创建一个名为employee.ser的文件。该程序不产生任何输出,但研究代码,并尝试确定该程序正在做什么。

- 将对象序列化到文件时,Java中的标准约定是给文件扩展名为.ser。

import java.io.*;
public class SerializeDemo {

   public static void main(String [] args) {
      Employee e = new Employee();
      e.name = "Reyan Ali";
      e.address = "Phokka Kuan, Ambehta Peer";
      e.SSN = 11122333;
      e.number = 101;
      
      try {
         FileOutputStream fileOut =
         new FileOutputStream("/tmp/employee.ser");
         ObjectOutputStream out = new ObjectOutputStream(fileOut);
         out.writeObject(e);
         out.close();
         fileOut.close();
         System.out.printf("Serialized data is saved in /tmp/employee.ser");
      }catch(IOException i) {
         i.printStackTrace();
      }
   }
}

反序列化对象

以下DeserializeDemo程序反序列化在SerializeDemo程序中创建的Employee对象。研究程序并尝试确定其输出 -

import java.io.*;
public class DeserializeDemo {

   public static void main(String [] args) {
      Employee e = null;
      try {
         FileInputStream fileIn = new FileInputStream("/tmp/employee.ser");
         ObjectInputStream in = new ObjectInputStream(fileIn);
         e = (Employee) in.readObject();
         in.close();
         fileIn.close();
      }catch(IOException i) {
         i.printStackTrace();
         return;
      }catch(ClassNotFoundException c) {
         System.out.println("Employee class not found");
         c.printStackTrace();
         return;
      }
      
      System.out.println("Deserialized Employee...");
      System.out.println("Name: " + e.name);
      System.out.println("Address: " + e.address);
      System.out.println("SSN: " + e.SSN);
      System.out.println("Number: " + e.number);
   }
}

输出结果如下 -

输出

Deserialized Employee...
Name: Reyan Ali
Address:Phokka Kuan, Ambehta Peer
SSN: 0
Number:101

以下要注意的要点如下:

Java - 网络

术语网络编程是指编写跨多个设备(计算机)执行的程序,其中设备都使用网络彼此连接。

J2SE API的java.net包包含提供低级别通信细节的类和接口的集合,允许您编写专注于解决现有问题的程序。

java.net包提供对两种常见网络协议的支持 -

本章对以下两个主题给予了很好的理解 -

套接字编程

套接字提供使用TCP的两台计算机之间的通信机制。客户端程序在通信结束时创建一个套接字,并尝试将该套接字连接到服务器。

当建立连接时,服务器在通信结束时创建一个套接字对象。客户端和服务器现在可以通过写入和从套接字读取来进行通信。

java.net.Socket类表示一个套接字,而java.net.ServerSocket类为服务器程序提供了一种侦听客户端并与其建立连接的机制。

在使用套接字的两台计算机之间建立TCP连接时,会发生以下步骤 -

建立连接后,可以使用I / O流进行通信。每个套接字都有一个OutputStream和一个InputStream。客户端的OutputStream连接到服务器的InputStream,客户端的InputStream连接到服务器的OutputStream。

TCP是双向通信协议,因此可以同时在两个流上发送数据。以下是提供完整的实现套接字方法的有用类。

ServerSocket类方法

java.net.ServerSocket中的类由服务器应用程序获得一个端口,监听客户端请求。

ServerSocket类有四个构造函数 -

没有 方法和说明
1

public ServerSocket(int port)抛出IOException

尝试创建绑定到指定端口的服务器套接字。如果端口已被其他应用程序绑定,则会发生异常。

2

public ServerSocket(int port,int backlog)抛出IOException

与之前的构造函数类似,backlog参数指定存储在等待队列中的传入客户端数量。

3

public ServerSocket(int port,int backlog,InetAddress address)抛出IOException

与以前的构造函数类似,InetAddress参数指定要绑定的本地IP地址。InetAddress用于可能具有多个IP地址的服务器,允许服务器指定哪个IP地址接受客户端请求。

4

public ServerSocket()抛出IOException

创建未绑定的服务器套接字。使用此构造函数时,在准备绑定服务器套接字时,请使用bind()方法。

如果ServerSocket构造函数不会引发异常,这意味着您的应用程序已成功绑定到指定的端口,并可以为客户端请求准备。

以下是ServerSocket类的一些常见方法 -

没有 方法和说明
1

public int getLocalPort()

返回服务器套接字正在侦听的端口。如果您在构造函数中作为端口号传递0,并让服务器为您找到一个端口,则此方法非常有用。

2

public Socket accept()抛出IOException

等待传入的客户端。该方法阻塞,直到客户端连接到指定端口上的服务器或套接字超时,假设超时值已使用setSoTimeout()方法设置。否则,此方法将无限期地阻止。

3

public void setSoTimeout(int timeout)

设置服务器套接字在accept()期间等待客户端的超时值。

4

public void bind(SocketAddress host,int backlog)

将套接字绑定到SocketAddress对象中指定的服务器和端口。如果您使用无参数构造函数实例化了ServerSocket,请使用此方法。

当ServerSocket调用accept()时,方法直到客户端连接才返回。客户端连接后,ServerSocket将在未指定的端口上创建一个新的Socket,并返回对此新Socket的引用。客户端和服务器之间现在存在TCP连接,并且可以开始通信。

套接字类方法

java.net.Socket中的类表示,无论是客户端和服务器使用相互沟通的插座。客户端通过实例化Socket对象,而服务器从accept()方法的返回值获取Socket对象。

Socket类有五个构造函数,客户端用于连接到服务器 -

没有 方法和说明
1

public Socket(String host,int port)throws UnknownHostException,IOException。

此方法尝试连接到指定端口上的指定服务器。如果此构造函数不会引发异常,则连接成功,并且客户端连接到服务器。

2

public Socket(InetAddress host,int port)抛出IOException

该方法与以前的构造函数相同,除了主机由InetAddress对象表示。

3

public Socket(String host,int port,InetAddress localAddress,int localPort)throws IOException。

连接到指定的主机和端口,在指定的地址和端口的本地主机上创建套接字。

4

public Socket(InetAddress主机,int端口,InetAddress localAddress,int localPort)抛出IOException。

此方法与以前的构造函数相同,只是主机由InetAddress对象而不是String表示。

5

public Socket()

创建一个未连接的套接字。使用connect()方法将此套接字连接到服务器。

当Socket构造函数返回时,它不会简单地实例化Socket对象,而是实际尝试连接到指定的服务器和端口。

这里列出了Socket类中的一些感兴趣的方法。请注意,客户端和服务器都有一个Socket对象,所以客户端和服务器都可以调用这些方法。

没有 方法和说明
1

public void connect(SocketAddress host,int timeout)throws IOException

该方法将套接字连接到指定的主机。只有当您使用无参数构造函数实例化Socket时,才需要此方法。

2

public InetAddress getInetAddress()

此方法返回该套接字连接到另一台计算机的地址。

3

public int getPort()

返回套接字在远程机器上绑定的端口。

4

public int getLocalPort()

返回套接字在本地机器上绑定的端口。

5

public SocketAddress getRemoteSocketAddress()

返回远程套接字的地址。

6

public InputStream getInputStream()抛出IOException

返回套接字的输入流。输入流连接到远程插座的输出流。

7

public OutputStream getOutputStream()抛出IOException

返回套接字的输出流。输出流连接到远程插座的输入流。

8

public void close()throws IOException

关闭套接字,这使得此Socket对象不再能够再次连接到任何服务器。

InetAddress类方法

此类表示Internet协议(IP)地址。以下是在执行套接字编程时需要的以下有用的方法 -

没有 方法和说明
1

static InetAddress getByAddress(byte [] addr)

给出给定原始IP地址的InetAddress对象。

2

static InetAddress getByAddress(String host,byte [] addr)

根据提供的主机名和IP地址创建InetAddress。

3

静态InetAddress getByName(String host)

确定主机名称的IP地址。

4

String getHostAddress()

返回文本显示中的IP地址字符string。

5

String getHostName()

获取此IP地址的主机名。

6

静态InetAddress InetAddress getLocalHost()

返回本地主机。

7

String toString()

将此IP地址转换为字符string。

套接字客户端示例

以下GreetingClient是通过使用套接字连接到服务器并发送问候语的客户端程序,然后等待响应。

// File Name GreetingClient.java
import java.net.*;
import java.io.*;

public class GreetingClient {

   public static void main(String [] args) {
      String serverName = args[0];
      int port = Integer.parseInt(args[1]);
      try {
         System.out.println("Connecting to " + serverName + " on port " + port);
         Socket client = new Socket(serverName, port);
         
         System.out.println("Just connected to " + client.getRemoteSocketAddress());
         OutputStream outToServer = client.getOutputStream();
         DataOutputStream out = new DataOutputStream(outToServer);
         
         out.writeUTF("Hello from " + client.getLocalSocketAddress());
         InputStream inFromServer = client.getInputStream();
         DataInputStream in = new DataInputStream(inFromServer);
         
         System.out.println("Server says " + in.readUTF());
         client.close();
      }catch(IOException e) {
         e.printStackTrace();
      }
   }
}

套接字服务器示例

以下GreetingServer程序是使用Socket类在由命令行参数指定的端口号上侦听客户端的服务器应用程序的示例 -

// File Name GreetingServer.java
import java.net.*;
import java.io.*;

public class GreetingServer extends Thread {
   private ServerSocket serverSocket;
   
   public GreetingServer(int port) throws IOException {
      serverSocket = new ServerSocket(port);
      serverSocket.setSoTimeout(10000);
   }

   public void run() {
      while(true) {
         try {
            System.out.println("Waiting for client on port " + 
               serverSocket.getLocalPort() + "...");
            Socket server = serverSocket.accept();
            
            System.out.println("Just connected to " + server.getRemoteSocketAddress());
            DataInputStream in = new DataInputStream(server.getInputStream());
            
            System.out.println(in.readUTF());
            DataOutputStream out = new DataOutputStream(server.getOutputStream());
            out.writeUTF("Thank you for connecting to " + server.getLocalSocketAddress()
               + "
Goodbye!");
            server.close();
            
         }catch(SocketTimeoutException s) {
            System.out.println("Socket timed out!");
            break;
         }catch(IOException e) {
            e.printStackTrace();
            break;
         }
      }
   }
   
   public static void main(String [] args) {
      int port = Integer.parseInt(args[0]);
      try {
         Thread t = new GreetingServer(port);
         t.start();
      }catch(IOException e) {
         e.printStackTrace();
      }
   }
}

编译客户端和服务器,然后启动服务器如下 -

$ java GreetingServer 6066
Waiting for client on port 6066...

检查客户端程序如下 -

输出

$ java GreetingClient localhost 6066
Connecting to localhost on port 6066
Just connected to localhost/127.0.0.1:6066
Server says Thank you for connecting to /127.0.0.1:6066
Goodbye!

Java - 发送电子邮件

使用Java应用程序发送电子邮件很简单,但首先应该在您的计算机上安装JavaMail APIJava Activation Framework(JAF)

下载并解压缩这些文件,在新创建的顶级目录中,您将会找到两个应用程序的大量jar文件。您需要在CLASSPATH添加mail.jaractivation.jar文件。

发送简单的电子邮件

以下是从您的机器发送简单电子邮件的示例。假设您的本地主机已连接到Internet,并且能够发送电子邮件。

// File Name SendEmail.java

import java.util.*;
import javax.mail.*;
import javax.mail.internet.*;
import javax.activation.*;

public class SendEmail {

   public static void main(String [] args) {    
      // Recipient"s email ID needs to be mentioned.
      String to = "abcd@gmail.com";

      // Sender"s email ID needs to be mentioned
      String from = "web@gmail.com";

      // Assuming you are sending email from localhost
      String host = "localhost";

      // Get system properties
      Properties properties = System.getProperties();

      // Setup mail server
      properties.setProperty("mail.smtp.host", host);

      // Get the default Session object.
      Session session = Session.getDefaultInstance(properties);

      try {
         // Create a default MimeMessage object.
         MimeMessage message = new MimeMessage(session);

         // Set From: header field of the header.
         message.setFrom(new InternetAddress(from));

         // Set To: header field of the header.
         message.addRecipient(Message.RecipientType.TO, new InternetAddress(to));

         // Set Subject: header field
         message.setSubject("This is the Subject Line!");

         // Now set the actual message
         message.setText("This is actual message");

         // Send message
         Transport.send(message);
         System.out.println("Sent message successfully....");
      }catch (MessagingException mex) {
         mex.printStackTrace();
      }
   }
}

编译并运行此程序发送简单的电子邮件 -

输出

$ java SendEmail
Sent message successfully....

如果要将电子邮件发送给多个收件人,则将使用以下方法指定多个电子邮件ID -

void addRecipients(Message.RecipientType type, Address[] addresses)
   throws MessagingException

这是参数的描述 -

发送一封HTML电子邮件

以下是从您的机器发送HTML电子邮件的示例。这里假设您的本地主机已连接到Internet,并且能够发送电子邮件。

这个例子与前一个非常相似,除了这里我们使用setContent()方法来设置第二个参数是“text / html”的内容来指定HTML内容被包含在消息中。

使用此示例,您可以发送像您喜欢的HTML内容一样大。

// File Name SendHTMLEmail.java

import java.util.*;
import javax.mail.*;
import javax.mail.internet.*;
import javax.activation.*;

public class SendHTMLEmail {

   public static void main(String [] args) {
      // Recipient"s email ID needs to be mentioned.
      String to = "abcd@gmail.com";

      // Sender"s email ID needs to be mentioned
      String from = "web@gmail.com";

      // Assuming you are sending email from localhost
      String host = "localhost";

      // Get system properties
      Properties properties = System.getProperties();

      // Setup mail server
      properties.setProperty("mail.smtp.host", host);

      // Get the default Session object.
      Session session = Session.getDefaultInstance(properties);

      try {
         // Create a default MimeMessage object.
         MimeMessage message = new MimeMessage(session);

         // Set From: header field of the header.
         message.setFrom(new InternetAddress(from));

         // Set To: header field of the header.
         message.addRecipient(Message.RecipientType.TO, new InternetAddress(to));

         // Set Subject: header field
         message.setSubject("This is the Subject Line!");

         // Send the actual HTML message, as big as you like
         message.setContent("<h1>This is actual message</h1>", "text/html");

         // Send message
         Transport.send(message);
         System.out.println("Sent message successfully....");
      }catch (MessagingException mex) {
         mex.printStackTrace();
      }
   }
}

编译并运行此程序发送HTML电子邮件 -

输出

$ java SendHTMLEmail
Sent message successfully....

在电子邮件中发送附件

以下是从机器发送带有附件的电子邮件的示例。这里假设您的本地主机连接到互联网,并且能够发送电子邮件。

// File Name SendFileEmail.java

import java.util.*;
import javax.mail.*;
import javax.mail.internet.*;
import javax.activation.*;

public class SendFileEmail {

   public static void main(String [] args) {     
      // Recipient"s email ID needs to be mentioned.
      String to = "abcd@gmail.com";

      // Sender"s email ID needs to be mentioned
      String from = "web@gmail.com";

      // Assuming you are sending email from localhost
      String host = "localhost";

      // Get system properties
      Properties properties = System.getProperties();

      // Setup mail server
      properties.setProperty("mail.smtp.host", host);

      // Get the default Session object.
      Session session = Session.getDefaultInstance(properties);

      try {
         // Create a default MimeMessage object.
         MimeMessage message = new MimeMessage(session);

         // Set From: header field of the header.
         message.setFrom(new InternetAddress(from));

         // Set To: header field of the header.
         message.addRecipient(Message.RecipientType.TO,new InternetAddress(to));

         // Set Subject: header field
         message.setSubject("This is the Subject Line!");

         // Create the message part 
         BodyPart messageBodyPart = new MimeBodyPart();

         // Fill the message
         messageBodyPart.setText("This is message body");
         
         // Create a multipar message
         Multipart multipart = new MimeMultipart();

         // Set text message part
         multipart.addBodyPart(messageBodyPart);

         // Part two is attachment
         messageBodyPart = new MimeBodyPart();
         String filename = "file.txt";
         DataSource source = new FileDataSource(filename);
         messageBodyPart.setDataHandler(new DataHandler(source));
         messageBodyPart.setFileName(filename);
         multipart.addBodyPart(messageBodyPart);

         // Send the complete message parts
         message.setContent(multipart );

         // Send message
         Transport.send(message);
         System.out.println("Sent message successfully....");
      }catch (MessagingException mex) {
         mex.printStackTrace();
      }
   }
}

编译并运行此程序发送HTML电子邮件 -

输出

$ java SendFileEmail
Sent message successfully....

用户认证部分

如果需要向电子邮件服务器提供用户ID和密码进行身份验证,则可以按如下方式设置这些属性:

props.setProperty("mail.user", "myuser");
props.setProperty("mail.password", "mypwd");

电子邮件发送机制的其余部分将保持如上所述。

Java - 多线程

Java是一种多线程编程语言,这意味着我们可以使用Java开发多线程程序。多线程程序包含两个或多个可同时运行的部件,每个部件可以同时处理不同的任务,从而最佳地利用可用资源,特别是当您的计算机有多个CPU时。

根据定义,多任务是当多个进程共享诸如CPU的公共处理资源时。多线程将多任务的概念扩展到可以将单个应用程序中的特定操作细分为单个线程的应用程序。每个线程可以并行运行。OS不仅在不同的应用程序之间划分处理时间,而且在应用程序中的每个线程之间划分处理时间。

多线程使您能够以同一程序同时进行多个活动的方式进行写入。

线程的生命周期

线程在其生命周期中经历了各个阶段。例如,线程诞生,启动,运行,然后死亡。下图显示了线程的完整生命周期。

Java线程

以下是生命周期的阶段 -

线程优先级

每个Java线程都有一个优先级,可以帮助操作系统确定安排线程的顺序。

Java线程优先级在MIN_PRIORITY(常数为1)和MAX_PRIORITY(常数为10)之间的范围内。默认情况下,每个线程都被赋予优先级NORM_PRIORITY(常数为5)。

具有较高优先级的线程对于一个程序来说更重要,应该在低优先级线程之前分配处理器时间。然而,线程优先级不能保证线程执行的顺序,并且依赖于平台。

通过实现Runnable接口创建一个线程

如果您的类旨在作为线程执行,那么您可以通过实现Runnable接口来实现此目的。您将需要遵循三个基本步骤 -

步骤1

作为第一步,您需要实现由Runnable接口提供的run()方法该方法为线程提供了一个入口点,您将把完整的业务逻辑放在此方法中。以下是run()方法的简单语法 -

public void run( )

第2步

作为第二步,您将使用以下构造函数实例化一个Thread对象 -

Thread(Runnable threadObj, String threadName);

其中,threadObj是实现Runnable接口的类的实例,threadName是给予新线程的名称。

步骤3

一旦创建了一个线程对象,您可以通过调用start()方法启动它,该方法执行对run()方法的调用。以下是一个简单的语法start()方法 -

void start();

这是一个创建一个新线程并开始运行的示例 -

class RunnableDemo implements Runnable {
   private Thread t;
   private String threadName;
   
   RunnableDemo( String name) {
      threadName = name;
      System.out.println("Creating " +  threadName );
   }
   
   public void run() {
      System.out.println("Running " +  threadName );
      try {
         for(int i = 4; i > 0; i--) {
            System.out.println("Thread: " + threadName + ", " + i);
            // Let the thread sleep for a while.
            Thread.sleep(50);
         }
      }catch (InterruptedException e) {
         System.out.println("Thread " +  threadName + " interrupted.");
      }
      System.out.println("Thread " +  threadName + " exiting.");
   }
   
   public void start () {
      System.out.println("Starting " +  threadName );
      if (t == null) {
         t = new Thread (this, threadName);
         t.start ();
      }
   }
}

public class TestThread {

   public static void main(String args[]) {
      RunnableDemo R1 = new RunnableDemo( "Thread-1");
      R1.start();
      
      RunnableDemo R2 = new RunnableDemo( "Thread-2");
      R2.start();
   }   
}

输出结果如下 -

输出

Creating Thread-1
Starting Thread-1
Creating Thread-2
Starting Thread-2
Running Thread-1
Thread: Thread-1, 4
Running Thread-2
Thread: Thread-2, 4
Thread: Thread-1, 3
Thread: Thread-2, 3
Thread: Thread-1, 2
Thread: Thread-2, 2
Thread: Thread-1, 1
Thread: Thread-2, 1
Thread Thread-1 exiting.
Thread Thread-2 exiting.

通过扩展线程类创建一个线程

创建线程的第二种方法是创建一个新类,使用以下两个简单的步骤来扩展Thread类。这种方法在处理使用Thread类中可用的方法创建的多个线程时提供了更多的灵活性。

步骤1

您将需要覆盖Thread类中可用的run()方法。该方法为线程提供了一个入口点,您将把完整的业务逻辑放在此方法中。以下是run()方法的简单语法 -

public void run( )

第2步

一旦创建了Thread对象,您可以通过调用start()方法启动它,该方法执行对run()方法的调用。以下是一个简单的语法start()方法 -

void start( );

这是以前的程序重写来扩展Thread -

class ThreadDemo extends Thread {
   private Thread t;
   private String threadName;
   
   ThreadDemo( String name) {
      threadName = name;
      System.out.println("Creating " +  threadName );
   }
   
   public void run() {
      System.out.println("Running " +  threadName );
      try {
         for(int i = 4; i > 0; i--) {
            System.out.println("Thread: " + threadName + ", " + i);
            // Let the thread sleep for a while.
            Thread.sleep(50);
         }
      }catch (InterruptedException e) {
         System.out.println("Thread " +  threadName + " interrupted.");
      }
      System.out.println("Thread " +  threadName + " exiting.");
   }
   
   public void start () {
      System.out.println("Starting " +  threadName );
      if (t == null) {
         t = new Thread (this, threadName);
         t.start ();
      }
   }
}

public class TestThread {

   public static void main(String args[]) {
      ThreadDemo T1 = new ThreadDemo( "Thread-1");
      T1.start();
      
      ThreadDemo T2 = new ThreadDemo( "Thread-2");
      T2.start();
   }   
}

输出结果如下 -

输出

Creating Thread-1
Starting Thread-1
Creating Thread-2
Starting Thread-2
Running Thread-1
Thread: Thread-1, 4
Running Thread-2
Thread: Thread-2, 4
Thread: Thread-1, 3
Thread: Thread-2, 3
Thread: Thread-1, 2
Thread: Thread-2, 2
Thread: Thread-1, 1
Thread: Thread-2, 1
Thread Thread-1 exiting.
Thread Thread-2 exiting.

线程方法

以下是Thread类中可用的重要方法的列表。

没有 方法和说明
1

public void start()

在单独的执行路径中启动线程,然后调用此Thread对象上的run()方法。

2

public void run()

如果使用单独的Runnable目标实例化了此Thread对象,则在该Runnable对象上调用run()方法。

3

public final void setName(String name)

更改Thread对象的名称。还有一个用于检索名称的getName()方法。

4

public final void setPriority(int priority)

设置此Thread对象的优先级。可能的值在1到10之间。

5

public final void setDaemon(boolean on)

true的参数表示此线程作为守护线程。

6

public final void join(long millisec)

当前线程在第二个线程上调用此方法,导致当前线程阻塞,直到第二个线程终止或指定的毫秒数通过。

7

public void interrupt()

中断此线程,导致它由于任何原因被阻止而继续执行。

8

public final boolean isAlive()

如果线程是活着的,那么线程启动之后,运行到完成之前的任何时间都会返回true。

以前的方法在一个特定的Thread对象上被调用。Thread类中的以下方法是静态的。调用其中一个静态方法对当前运行的线程执行操作。

没有 方法和说明
1

public static void yield()

导致当前运行的线程屈服于任何其他正在等待调度的优先级的其他线程。

2

public static void sleep(long millisec)

使当前正在运行的线程至少阻塞指定的毫秒数。

3

public static boolean holdingLock(Object x)

如果当前线程持有给定对象的锁,则返回true。

4

public static Thread currentThread()

返回对当前正在运行的线程的引用,该线程是调用此方法的线程。

5

public static void dumpStack()

打印当前正在运行的线程的堆栈跟踪,这在调试多线程应用程序时非常有用。

以下ThreadClassDemo程序演示了Thread类的一些这些方法。考虑一个类DisplayMessage实现Runnable -

// File Name : DisplayMessage.java
// Create a thread to implement Runnable

public class DisplayMessage implements Runnable {
   private String message;
   
   public DisplayMessage(String message) {
      this.message = message;
   }
   
   public void run() {
      while(true) {
         System.out.println(message);
      }
   }
}

以下是扩展Thread类的另一个类 -

// File Name : GuessANumber.java
// Create a thread to extentd Thread

public class GuessANumber extends Thread {
   private int number;
   public GuessANumber(int number) {
      this.number = number;
   }
   
   public void run() {
      int counter = 0;
      int guess = 0;
      do {
         guess = (int) (Math.random() * 100 + 1);
         System.out.println(this.getName() + " guesses " + guess);
         counter++;
      } while(guess != number);
      System.out.println("** Correct!" + this.getName() + "in" + counter + "guesses.**");
   }
}

以下是主程序,它利用上面定义的类 -

// File Name : ThreadClassDemo.java
public class ThreadClassDemo {

   public static void main(String [] args) {
      Runnable hello = new DisplayMessage("Hello");
      Thread thread1 = new Thread(hello);
      thread1.setDaemon(true);
      thread1.setName("hello");
      System.out.println("Starting hello thread...");
      thread1.start();
      
      Runnable bye = new DisplayMessage("Goodbye");
      Thread thread2 = new Thread(bye);
      thread2.setPriority(Thread.MIN_PRIORITY);
      thread2.setDaemon(true);
      System.out.println("Starting goodbye thread...");
      thread2.start();

      System.out.println("Starting thread3...");
      Thread thread3 = new GuessANumber(27);
      thread3.start();
      try {
         thread3.join();
      }catch(InterruptedException e) {
         System.out.println("Thread interrupted.");
      }
      System.out.println("Starting thread4...");
      Thread thread4 = new GuessANumber(75);
      
      thread4.start();
      System.out.println("main() is ending...");
   }
}

输出结果如下。您可以一次又一次地尝试这个例子,每次都会得到不同的结果。

输出

Starting hello thread...
Starting goodbye thread...
Hello
Hello
Hello
Hello
Hello
Hello
Goodbye
Goodbye
Goodbye
Goodbye
Goodbye
.......

主要Java多线程概念

在Java中进行多线程编程时,您需要具有以下概念:

Java - Applet基础知识

一个小程序是在Web浏览器中运行的Java程序。小程序可以是一个功能齐全的Java应用程序,因为它具有完整的Java API。

applet和独立Java应用程序之间有一些重要的区别,包括以下内容:

小程序的生命周期

Applet类中的四种方法为您提供创建任何严重applet的框架 -

一个“你好,世界”小程序

以下是一个名为HelloWorldApplet.java的简单小程序 -

import java.applet.*;
import java.awt.*;

public class HelloWorldApplet extends Applet {
   public void paint (Graphics g) {
      g.drawString ("Hello World", 25, 50);
   }
}

这些import语句把类放在我们的applet类的范围内 -

没有这些import语句,Java编译器将无法识别applet类引用的类Applet和Graphics。

小程序类

每个小程序都是java.applet.Applet类扩展基础Applet类提供派生的Applet类可以从浏览器上下文中调用以获取信息和服务的方法。

这些包括执行以下操作的方法 -

此外,Applet类提供了一个界面,通过该接口,查看器或浏览器可以获取关于小程序的信息并控制小程序的执行。观众可能 -

Applet类提供了每种方法的默认实现。这些实现可以根据需要被覆盖。

“Hello,World”小程序是完整的。覆盖的唯一方法是涂漆方法。

调用Applet

可以通过将指令嵌入到HTML文件中并通过Applet浏览器或支持Java的浏览器查看文件来调用小程序。

<applet>标签是将小程序嵌入到HTML文件中的基础。以下是一个调用“Hello,World”小程序的例子,

<html>
   <title>The Hello, World Applet</title>
   <hr>
   <applet code = "HelloWorldApplet.class" width = "320" height = "120">
      If your browser was Java-enabled, a "Hello, World"
      message would appear here.
   </applet>
   <hr>
</html>

注意 - 您可以参考HTML小程序标签来了解更多关于从HTML调用applet。

<applet>标签的代码属性是必需的。它指定要运行的Applet类。还需要宽度和高度来指定小程序运行的面板的初始大小。applet指令必须用</ applet>标签关闭。

如果小程序获取参数,则可以通过在<applet>和</ applet>之间添加<param>标签来为参数传递值。浏览器忽略小程序标签之间的文本和其他标签。

非Java启用浏览器不处理<applet>和</ applet>。因此,与非applet相关的标签之间出现的任何内容在非启用Java的浏览器中都可见。

查看器或浏览器在文档的位置查找编译的Java代码。要指定,请使用<applet>标签的codebase属性,如图所示 -

<applet codebase = "https://amrood.com/applets" code = "HelloWorldApplet.class"
   width = "320" height = "120">

如果一个applet驻留在默认的包中,则必须使用句点(。)在代码属性中指定保持包以分隔包/类组件。例如 -

<applet  = "mypackage.subpackage.TestApplet.class" 
   width = "320" height = "120">

获取Applet参数

以下示例演示如何使applet响应文档中指定的设置参数。该小程序显示黑色和第二种颜色的棋盘图案。

可以将第二种颜色和每个正方形的大小指定为文档中的小程序的参数。

CheckerApplet在init()方法中获取参数。它也可以在paint()方法中获得它的参数。但是,在小程序开始时获取值并保存设置一次,而不是每次刷新,方便而有效。

applet查看器或浏览器调用它运行的每个小程序的init()方法。查看器在加载小程序后立即调用init()一次。(Applet.init()被实现为不执行任何操作。)覆盖默认实现以插入自定义初始化代码。

Applet.getParameter()方法获取给定参数名称的参数(参数的值始终为字符string)。如果值是数字或其他非字符数据,则必须解析该字符string。

以下是CheckerApplet.java的骨架 -

import java.applet.*;
import java.awt.*;

public class CheckerApplet extends Applet {
   int squareSize = 50;   // initialized to default size
   public void init() {}
   private void parseSquareSize (String param) {}
   private Color parseColor (String param) {}
   public void paint (Graphics g) {}
}

这里是CheckerApplet的init()和private parseSquareSize()方法 -

public void init () {
   String squareSizeParam = getParameter ("squareSize");
   parseSquareSize (squareSizeParam);
   
   String colorParam = getParameter ("color");
   Color fg = parseColor (colorParam);
   
   setBackground (Color.black);
   setForeground (fg);
}

private void parseSquareSize (String param) {
   if (param == null) return;
   try {
      squareSize = Integer.parseInt (param);
   }catch (Exception e) {
      // Let default value remain
   }
}

小程序调用parseSquareSize()来解析squareSize参数。parseSquareSize()调用库方法Integer.parseInt(),它解析一个字符string并返回一个整数。Integer.parseInt()只要参数无效就抛出异常。

因此,parseSquareSize()捕获异常,而不是允许小程序在坏输入上失败。

小程序调用parseColor()来将颜色参数解析为颜色值。parseColor()执行一系列字符string比较,以将参数值与预定义颜色的名称进行匹配。您需要实现这些方法来使此applet工作。

指定Applet参数

以下是嵌入了CheckerApplet的HTML文件的示例。HTML文件通过<param>标签指定小程序的两个参数。

<html>
   <title>Checkerboard Applet</title>
   <hr>
   <applet code = "CheckerApplet.class" width = "480" height = "320">
      <param name = "color" value = "blue">
      <param name = "squaresize" value = "30">
   </applet>
   <hr>
</html>

- 参数名称不区分大小写。

应用程序转换为Applet

将图形化的Java应用程序(即使用AWT的应用程序,您可以从Java程序启动器开始)转换为可嵌入网页的小程序很容易。

以下是将应用程序转换为小程序的具体步骤。

事件处理

Applet从Container类继承了一组事件处理方法。Container类定义了几种方法,例如processKeyEvent和processMouseEvent,用于处理特定类型的事件,然后是一个称为processEvent的全部方法。

为了对事件作出反应,小程序必须覆盖适当的事件特定方法。

import java.awt.event.MouseListener;
import java.awt.event.MouseEvent;
import java.applet.Applet;
import java.awt.Graphics;

public class ExampleEventHandling extends Applet implements MouseListener {
   StringBuffer strBuffer;

   public void init() {
      addMouseListener(this);
      strBuffer = new StringBuffer();
      addItem("initializing the apple ");
   }

   public void start() {
      addItem("starting the applet ");
   }

   public void stop() {
      addItem("stopping the applet ");
   }

   public void destroy() {
      addItem("unloading the applet");
   }

   void addItem(String word) {
      System.out.println(word);
      strBuffer.append(word);
      repaint();
   }

   public void paint(Graphics g) {
      // Draw a Rectangle around the applet"s display area.
      g.drawRect(0, 0, 
      getWidth() - 1,
      getHeight() - 1);

      // display the string inside the rectangle.
      g.drawString(strBuffer.toString(), 10, 20);
   }

   
   public void mouseEntered(MouseEvent event) {
   }
   public void mouseExited(MouseEvent event) {
   }
   public void mousePressed(MouseEvent event) {
   }
   public void mouseReleased(MouseEvent event) {
   }
   public void mouseClicked(MouseEvent event) {
      addItem("mouse clicked! ");
   }
}

现在,让我们称之为applet如下:

<html>
   <title>Event Handling</title>
   <hr>
   <applet code = "ExampleEventHandling.class" 
      width = "300" height = "300">
   </applet>
   <hr>
</html>

最初,小程序将显示“初始化小程序,启动小程序”。然后一旦点击矩形,“鼠标点击”也将显示。

显示图像

小程序可以显示GIF,JPEG,BMP等格式的图像。要在小程序中显示图像,请使用java.awt.Graphics类中的drawImage()方法。

以下是显示图像的所有步骤的示例 -

import java.applet.*;
import java.awt.*;
import java.net.*;

public class ImageDemo extends Applet {
   private Image image;
   private AppletContext context;
   
   public void init() {
      context = this.getAppletContext();
      String imageURL = this.getParameter("image");
      if(imageURL == null) {
         imageURL = "java.jpg";
      }
      try {
         URL url = new URL(this.getDocumentBase(), imageURL);
         image = context.getImage(url);
      }catch(MalformedURLException e) {
         e.printStackTrace();
         // Display in browser status bar
         context.showStatus("Could not load image!");
      }
   }
   
   public void paint(Graphics g) {
      context.showStatus("Displaying image");
      g.drawImage(image, 0, 0, 200, 84, null);
      g.drawString("www.javalicense.com", 35, 100);
   }  
}

现在,让我们称之为applet如下:

<html>
   <title>The ImageDemo applet</title>
   <hr>
   <applet code = "ImageDemo.class" width = "300" height = "200">
      <param name = "image" value = "java.jpg">
   </applet>
   <hr>
</html>

播放音频

Applet可以播放java.applet包中的AudioClip接口所代表的音频文件。AudioClip界面有三种方法,包括 -

要获取AudioClip对象,必须调用Applet类的getAudioClip()方法。getAudioClip()方法立即返回,无论URL是否解析为实际的音频文件。在尝试播放音频剪辑之前,音频文件不会被下载。

以下是演示播放音频的所有步骤的示例 -

import java.applet.*;
import java.awt.*;
import java.net.*;

public class AudioDemo extends Applet {
   private AudioClip clip;
   private AppletContext context;
   
   public void init() {
      context = this.getAppletContext();
      String audioURL = this.getParameter("audio");
      if(audioURL == null) {
         audioURL = "default.au";
      }
      try {
         URL url = new URL(this.getDocumentBase(), audioURL);
         clip = context.getAudioClip(url);
      }catch(MalformedURLException e) {
         e.printStackTrace();
         context.showStatus("Could not load audio file!");
      }
   }
   
   public void start() {
      if(clip != null) {
         clip.loop();
      }
   }
   
   public void stop() {
      if(clip != null) {
         clip.stop();
      }
   }
}

现在,让我们称之为applet如下:

<html>
   <title>The ImageDemo applet</title>
   <hr>
   <applet code = "ImageDemo.class" width = "0" height = "0">
      <param name = "audio" value = "test.wav">
   </applet>
   <hr>
</html>

您可以在PC上使用test.wav来测试上述示例。

Java - 文档注释

Java语言支持三种类型的注释 -

没有 注释和说明
1

/ * text * /

编译器忽略从/ *到* /的所有内容。

2

//文本

编译器忽略从//到行尾的所有内容。

3

/ **文件* /

这是一个文档注释,一般来说它被称为doc注释JDK的javadoc工具使用文档注释准备自动生成的文档时。

本章是关于解释Javadoc的。我们将看到我们如何利用Javadoc来生成有用的Java代码文档。

什么是Javadoc?

Javadoc是一个JDK附带的工具,它用于从Java源代码生成HTML格式的Java代码文档,需要以预定格式的文档。

Following is a simple example where the lines inside /*….*/ are Java multi-line comments. Similarly, the line which preceeds // is Java single-line comment.

Example

/**
* The HelloWorld program implements an application that
* simply displays "Hello World!" to the standard output.
*
* @author  Zara Ali
* @version 1.0
* @since   2014-03-31 
*/
public class HelloWorld {

   public static void main(String[] args) {
      /* Prints Hello, World! on standard output.
      System.out.println("Hello World!");
   }
}

You can include required HTML tags inside the description part. For instance, the following example makes use of <h1>....</h1> for heading and <p> has been used for creating paragraph break -

Example

/**
* <h1>Hello, World!</h1>
* The HelloWorld program implements an application that
* simply displays "Hello World!" to the standard output.
* <p>
* Giving proper comments in your program makes it more
* user friendly and it is assumed as a high quality code.
* 
*
* @author  Zara Ali
* @version 1.0
* @since   2014-03-31 
*/
public class HelloWorld {

   public static void main(String[] args) {
      /* Prints Hello, World! on standard output.
      System.out.println("Hello World!");
   }
}

The javadoc Tags

The javadoc tool recognizes the following tags -

Tag Description Syntax
@author Adds the author of a class. @author name-text
{@code} Displays text in code font without interpreting the text as HTML markup or nested javadoc tags. {@code text}
{@docRoot} Represents the relative path to the generated document"s root directory from any generated page. {@docRoot}
@deprecated Adds a comment indicating that this API should no longer be used. @deprecated deprecatedtext
@exception Adds a Throws subheading to the generated documentation, with the classname and description text. @exception class-name description
{@inheritDoc} Inherits a comment from the nearest inheritable class or implementable interface. Inherits a comment from the immediate surperclass.
{@link} Inserts an in-line link with the visible text label that points to the documentation for the specified package, class, or member name of a referenced class. {@link package.class#member label}
{@linkplain} Identical to {@link}, except the link"s label is displayed in plain text than code font. {@linkplain package.class#member label}
@param Adds a parameter with the specified parameter-name followed by the specified description to the "Parameters" section. @param parameter-name description
@return Adds a "Returns" section with the description text. @return description
@see Adds a "See Also" heading with a link or text entry that points to reference. @see reference
@serial Used in the doc comment for a default serializable field. @serial field-description | include | exclude
@serialData Documents the data written by the writeObject( ) or writeExternal( ) methods. @serialData data-description
@serialField Documents an ObjectStreamField component. @serialField field-name field-type field-description
@since Adds a "Since" heading with the specified since-text to the generated documentation. @since release
@throws The @throws and @exception tags are synonyms. @throws class-name description
{@value} When {@value} is used in the doc comment of a static field, it displays the value of that constant. {@value package.class#field}
@version Adds a "Version" subheading with the specified version-text to the generated docs when the -version option is used. @version version-text

Example

Following program uses few of the important tags available for documentation comments. You can make use of other tags based on your requirements.

The documentation about the AddNum class will be produced in HTML file AddNum.html but at the same time a master file with a name index.html will also be created.

import java.io.*;

/**
* <h1>Add Two Numbers!</h1>
* The AddNum program implements an application that
* simply adds two given integer numbers and Prints
* the output on the screen.
* <p>
* <b>Note:</b> Giving proper comments in your program makes it more
* user friendly and it is assumed as a high quality code.
*
* @author  Zara Ali
* @version 1.0
* @since   2014-03-31
*/
public class AddNum {
   /**
   * This method is used to add two integers. This is
   * a the simplest form of a class method, just to
   * show the usage of various javadoc Tags.
   * @param numA This is the first paramter to addNum method
   * @param numB  This is the second parameter to addNum method
   * @return int This returns sum of numA and numB.
   */
   public int addNum(int numA, int numB) {
      return numA + numB;
   }

   /**
   * This is the main method which makes use of addNum method.
   * @param args Unused.
   * @return Nothing.
   * @exception IOException On input error.
   * @see IOException
   */

   public static void main(String args[]) throws IOException {
      AddNum obj = new AddNum();
      int sum = obj.addNum(10, 20);

      System.out.println("Sum of 10 and 20 is :" + sum);
   }
}

Now, process the above AddNum.java file using javadoc utility as follows -

$ javadoc AddNum.java
Loading source file AddNum.java...
Constructing Javadoc information...
Standard Doclet version 1.7.0_51
Building tree for all the packages and classes...
Generating /AddNum.html...
AddNum.java:36: warning - @return tag cannot be used in method with void return type.
Generating /package-frame.html...
Generating /package-summary.html...
Generating /package-tree.html...
Generating /constant-values.html...
Building index for all the packages and classes...
Generating /overview-tree.html...
Generating /index-all.html...
Generating /deprecated-list.html...
Building index for all classes...
Generating /allclasses-frame.html...
Generating /allclasses-noframe.html...
Generating /index.html...
Generating /help-doc.html...
1 warning
$

You can check all the generated documentation here - AddNum. If you are using JDK 1.7 then javadoc does not generate a great stylesheet.css, so we suggest to download and use standard stylesheet from https://docs.oracle.com/javase/7/docs/api/stylesheet.css