Java日期时间
java.uti包提供了Date类来封装当前的日期和时间
Data() 构造函数使用当前日期和时间来初始化对象
Data(long millisec) 构造函数接收一个参数从1970年1月1日起的毫秒数
获取当前日期时间
import java.util.Date;
public class DateDemo{
public static void main(String args[]){
//初始化Date对象
Date date = new Date();
//使用toString()函数显示日期时间
sout(data.toString());
}
}
运行结果:
Mon May 04 09:51:52 CDT 2013
使用SimpleDateFormat格式化时间
SimpleDateFormat是一个以语言环境敏感的方式来格式化和分析日期的类。允许你选择任何用户自定义日期时间格式来运行
import java.util.*;
import java.test.*;
public class DateDemo{
public static void main(String args[]){
Date dNow = new Date(); //DateFormat格式化编码
SimpleDateFormat ft = new SimpleDateFormat("E yyyy.MM.dd 'at' hh:mm:ss a zzz");
sout("Current Date: " + ft.format(dNow));
}
}
运行结果:
Current Date: Sun 2004.07.18 at 04:14:09 PM PDT
Java休眠(sleep)
下面的程序会休眠3秒
import java.util.*;
public static void main(String args[]){
try{
sout(new Date() + "\n");
Thread.sleep(5*60*10); //1秒 = 1000毫秒
sout(new Date() + "\n");
} catch(Exception e){
sout("Got an exception!");
}
}
}
Calendar类
Calendar类是一个抽象类,在实际使用时实现特定的子类的对象,创建对象的过程只需要使用getInstance方法创建即可
创建一个代表系统当前日期的Calendar对象
- Get设置
//获得年份
int year = c1.get(Calendar.YEAR);
- Set设置
Calendar c1 = Calendar.getInstance(); //默认是当前日期
public void set(int field, int value)
c1.set(Calendar.DATE, 10);
c1.set(Calendar.YEAR, 2008);
- Add设置
把c1对象的日期加上10,也就是c1所表的日期的10天后的日期,其他所有的数值都会被重新计算
c1.add(Calendar.DATE, 10);
Calendar类实现了公历日历,GregorianCalenda是Calendar类的一个具体实现
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;
//初始化Gregorian日历
//使用当前时间和日期
//默认为本地时间和时区
GergorianCalendar gcalendar = new GergorianCalendar();
//显示当前时间和日期的信息 sout 为 print 不是 println
sout("Date: ");
sout("months[gcalendar.get(Calendar.MONTH)]");
sout(" " + gcalendar.get(Calendar.DATE) + " ");
sout(year = gcalendar.get(Calendar.YEAR));
sout("Time: ");
sout(gcalendar.get(Calendar.HOUR) + ":");
sout(gcalendar.get(Calendar.MINUTE) + ":");
sout(gcalendar.get(Calendar.SECOND));
//测试当前年份是否为闰年
if(gcalendar.isLeapYeay(year)){
sout("当前年份是闰年");
}
else {
sout("当前年份不是闰年");
}
}
}
运行结果:
Date: Apr 22 2009
Time: 11:25:27
当前年份不是闰年
Java方法
System.out.println()
println()是一个方法(Method),而System是系统类(Class),out是标准输出对象(Object)
这句话的用法是调用系统类System中的标准输出对象out中的方法println()
方法的定义
修饰符 返回值类型 方法名 (参数类型 参数名){
...
方法体
...
return 返回值:
}
- 修饰符:是可选的,告诉编译器如何调用该方法,定义了该方法的访问类型
- 返回值类型:方法可能会返回值。returnValueType是关键字void
- 方法名:是方法的实际名称
- 参数类型:当方法被调用时,传递值给参数。这个值被称为实参或变量。参数列表是指方法的参数类型、顺序和参数的个数
- 方法体:方法体包括具体的语句,定义该方法的功能
void方法的调用一定是一个语句,没有返回值,像任何以分号结束的语句一样
通过值传递参数
连续n次打印一个消息:
public static void nPrintln(String message, int n){
for(int i = 0; i < n; i++)
sout(message);
}
方法的重载
一个类的两个方法拥有相同的名字,但是有不同的参数列表
构造方法
当一个对象被创建时候,构造方法用来初始化该对象。构造方法和它所在类的名字相同,但构造方法没有返回值。
通常会使用构造方法给一个类的实例变量赋初值,或者执行其他必要的步骤来创建一个完整的对象
不管你是否自定义构造方法,所有的类都有构造方法,因为Java自动提供了一个默认构造方法,它会把所有成员初始化为0
//一个简单的构造函数
static class Myclass{
int x;
//以下是构造函数
MyClass(int i){
x = i;
}
}
//调用构造方法来初始化一个对象
public class ConsDemo{
public static void main(String args[]){
MyClass t1 = new MyClass(10);
MyClass t2 = new MyClass(20);
sout(t1.x + " " + t2.x);
}
}
运行结果:
10 20
可变参数
Java支持传递同类型的可变参数给一个方法
typeName...parameterName
在方法声明中,在指定参数类型后加一个省略号(…)
一个方法中只能指定一个可变参数,它必须是方法的最后一个参数,任何普通的参数必须在它之前声明
public calss VarageDemo{
public static void main(String args[]){
//调用可变参数的方法
printMax{34,3,3,2,56.5};
printMax(new double[]{1,2,3});
}
public static void printMax(double...numbers){
if(numbers.length == 0){
sout("No argument passed");
return;
}
double result = numbers[0];
for(int i = 1; i < number.length; i++)
if(number[i] > result){
result = numbers[i];
}
sout("The max value is " + result);
}
}
Java流(Stream)、文件(File) 和 IO
Java.io包几乎包括了所有操作输入、输出需要的类。所有这些流类代表了输入源和输出目标
一个流可以理解为一个数据的序列、输入流表示一个源读取数据,输出流表示一个目标写数据。
读取控制台输入
Java的控制台输入由System.in完成
为了获得一个绑定到控制台的字符流,你可以把System.in包装在一个BufferedReader对象中创建一个字符流
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
BufferedReader对象创建后,我们可以使用read()方法从控制台读取一个字符,或者用readLine()方法读取一个字符串
从控制台读取多字符输入
从BufferedReader对象读取一个字符要使用**read()**方法
从BufferedReader对象读取一个字符串要使用**readLine()**方法
int read() throws IOException
每次调用read()方法,它从输入流读取一个字符并把该字符作为整数值返回。当流结束的时候返回-1。该方法抛出IOException
下面的程序用read()方法从控制台不断读取字符知道用户输入”q”
//使用BufferedReader 在控制台读取字符
import java.io.*;
public class BRRead{
public static void main(String args[]) throws IOException{
char c;
//使用System.in创建BufferedReader
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
sout("输入字符,按下'q'键退出.");
//读取字符
do{
c = (char) br.read();
//c = br.readLine();
sout(c);
} while(c != 'q');
}
}
运行结果:
输入字符,按下'q'键退出.
123abcq
1
2
3
a
b
c
q
FileInputStream
该流用于从文件读取数据,它的对象可以用关键字new来创建,有多重构造方法可用来创建对象。
可以使用字符串类型的文件名来创建一个输入流对象来读取文件:
InputStream f = new FileInputStream("C:/java/hello");
也可以使用一个文件对象来创建一个输入流对象来读取文件,先使用File()方法创建一个文件对象
File f = new File("C:/java/hello");
InputStream f = new FileInputStream(f);
FileOutputStream
该类用来创建一个文件并向文件中写数据
如果该流在打开文件进行输出前,目标文件不存在,那么该流会创建该文件
有两个构造方法可以用来创建FileOutputStream对象
使用字符串类型的文件名来创建一个输出流对象
OutputStream f = new FileOutputStream("C:/java/hello");
也可以使用一个文件对象来创建一个输出流来写文件,先使用File()方法创建一个文件对象
File f = new File("C:/java/hello");
OutputStream f = new FileOutputStream(f);
Java中的目录
创建目录:
File类中有两个方法可以用来创建文件夹:
- **mkdir()**方法创建一个文件夹,成功则返回true,失败则返回false,失败表明File对象指定的路径已经存在,或者由于整个路径害不存在,该文件夹不能被创建
- **mkdirs()**方法创建一个文件夹和它的所有父文件夹
Java Scanner类
Scanner对象的基本语法:
Scanner s = new Scanner(System.in);
通过Scanner类的next() 与 **nextLine()**方法获取输入的字符串
在读取前我们需要使用 hasNext 与 hasNextLine 判断是否还有输入数据。
使用next方法:
import java.util.Scanner;
public class ScannerDemo{
public static void main(String args[]){
Scanner scan = new Scanner(System.in);
sout("next方式接收:");
//判断是否还有输入
if(scan.hasNext()){
String str1 = scan.next();
sout("输入的数据为: " + str1);
}
}
}
输出结果:
next方式接收
youj com
输入的数据为:youj
使用nextLine方法:
import java.util.Scanner;
public class ScannerDemo{
public static void main(String[] args){
Scanner scan = new Scanner(System.in);
sout("nextLine方式接收: ");
//判断是否还有输入
if(scan.hasNextLine()){
String str2 = scan.nextLine();
sout("输入的数据为: " + str2);
}
}
}
输出结果:
next方式接收
youj com
输入的数据为:youj com
next() 与 nextLine() 区别
next():
- 一定要读取到有效字符后才可以结束输入
- 对输入有效字符之前遇到的空白,next()方法胡自动将其去掉
- 只有输入有效字符才能将其后面输入的空白作为分隔符或结束符
- next()不能得到带有空格的字符串
nextLine():
- 以Enter为结束符,也就是说nextLine()方法返回的是输入回车之前的所有字符
- 可以获得空白
如果要输入int或float类型的数据,在Scanner类中也有支持,但是在输入之前最好先使用hasNextXxx() 方法进行验证,再使用 nextXxx()来读取:
import java.util.Scanner;
public calss ScannerDemo{
public static void main(String args[]){
Scanner scan = new Scanner(System.in);
int i = 0;
float f = 0.0f;
sout("输入整数: ");
if(scan.hasNextInt()){
//判断输入的是否是整数
i = scan.nextInt();
sout("整数数据: " + i);
} else{
sout("输入的不是整数!");
}
sout("输入小数: ");
if(scan.hasNextFloat()){
//判断输入的是否是小数
f = scan.nextFloat();
sout("小数数据: " + f);
} else{
sout("输入的不是小数!");
}
}
}
Java异常处理
捕获异常 try/catch
使用 try 和 catch关键字可以捕获异常,try/catch 代码块中的代码成为保护代码
try{
//见识代码执行过程,一旦发现异常则直接跳转至catch,
//如果没有异常则直接跳转至finally
} catch (ExceptionName e1){
//Catch快 可选执行的代码块,如果没有任何异常发生不会执行
//如果发现异常则进行处理或向上抛出
} finally{
//必选执行的代码块,不管是否有异常发生
//及时发生内存溢出异常也会执行,通常用于处理善后清理工作
}
throws/throw关键字
如果一个方法没有捕获一个检查性异常,那么该方法必须使用throws关键字来声明
一个方法可以声明抛出多个异常,多个异常之间用逗号隔开
import java.io.*;
public class className{
public void withdraw(double amount) throws RemoteException, InsufficientFundsException{
//...
}
}
finally关键字
用来创建在try代码块后面执行的最后一个 代码块,无论是否发生异常,finally代码块中的代码总会被执行
小综合
public class ExcepTest{
public static void main(String args[]){
int a[] = new int[2];
try{
sout("Access element three :" + a[3]);
} catch(ArrayIndexOutOfBoundsException e){
sout("Exception thrown :" + e);
} finally{
a[0] = 6;
sout("First element value: " + a[0]);
sout("The finally statement is executed");
}
}
}
运行结果:
Exception thrown :java.l
Java继承
如果类A是类B的父亲,而类B是类C的父亲,我们也称类C是A的子类,类C是从类A继承而来的,在Java中,类的继承是单一继承,一个子类只能拥有一个父类。
继承中最常使用的两个关键词是extends和implements
这两个关键字的使用决定了一个对象和另一个对象是否是一个关系,我们能实现一个对象获取另一个对象的属性
所有Java的类均是由java.lang.Object类继承而来的,所以Object是所有类的祖先类,而除了Object外,所有类必须有一个父类。
通过extends关键字可以申明一个类是继承另一个类而来的
public class A{
private int i;
protected int j;
public void func(){
}
}
public class B extends A{
public int z;
public void fund(){
}
}
类B由类A继承而来的,类B是类A的子类,而类A是Object的子类,这里可以不显示地声明
作为子类,类B的实例拥有类A所有的成员变量,但对于private类型的成员变量类B却没有访问权限
这保障了类A的封装性
public class Animal{}
public class Mammal extends Animal{} Animal类是Mammal类的父类
public class Reptile extends Animal{} Animal类是Reptile类的父类
Mammal类和Reptile类是Animal类的子类
public class Dog extends Mammal{} Dog类既是Mammal类的子类 又是 Animal类的子类
//通过使用关键字 extends,子类可以继承父类的除privat属性外所有的属性
//通过使用 instanceof 操作符,能够确定左边的对象是不是右边类的实例
public class Dog extends Mammal{
public static void main(String args[]){
Animal a = new Animal();
Mammal m = new Mammal();
Dog d = new Dog();
sout(m instanceof Animal);
sout(d instanceof Mammal);
sout(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类将实现的细节对用户隐藏起来,因此,用户只需要知道怎样调用Van类来完成某一功能
//而不必知道Van类是自己来做还是调用其他类来做这些工作
Java只支持单继承,一个类不能继承多个类
(×) public class test extends Animal, Mammal{} (×)
Java只支持单继承(继承基本类和抽象类),可以用接口来实现(多继承接口实现)
public class Apple extends Fruit implements Fruit1, Fruit2{}
一般继承基本类和抽象类用extends关键字,实现接口类的继承用implements关键字。
重写
重写重要的地方是返回值和形参都不能改变,外壳不变,核心重写!
重写的好处在于子类可以根据需要,定义特定与自己的行为。
class Animal{
public void move(){
sout("动物可以移动");
}
}
class Dog extends Animal{
public void move(){
sout("狗可以跑和走");
}
/*
public void bark(){
sout("狗可以吠叫");
}
*/
}
public class TestDog{
public static void main(String args[]){
Animal a = new Animal();
Animal b = new Dog();
a.move();
b.move();
// a.bark();//此处会报错,因为a的引用类型Animal没有bark方法
}
}
运行结果:
动物可以移动
狗可以跑和走
尽管b属于Animal类型,但是它可以运行Dog类的move方法
方法重写的规则
- 参数列表与被重写方法的参数列表必须完全相同
- 返回类型与被重写方法的返回类型可以不相同,但是必须是父类返回值的派生类
- 子类方法的访问权限必须大于或等于父类方法的访问权限:如果父类的一个方法被声明为public,那么在子类中重写该方法就不能声明为protected
- 父类的成员方法只能被它的子类重写
- 声明为final的方法不能被重写
- 声明为static的方法不能被重写,但可以被再次声明
- 子类和父类在同一个包中,那么子类可以重写父类所有方法,除了声明为private和final的方法
- 子类和父类不在同一个包中,那么子类可以重写父类的声明为public和protected的非final方法
- 构造方法不能被重写
- 如果不能继承一个方法,则不能重写这个方法
- 权限受阻:如果父类的一个方法被声明为public,那么在子类中重写该方法就不能声明为protected
Super关键字的使用
当需要在子类中调用父类的被重写方法时,要使用super关键字
class Animal{
public void move(){
sout("动物可以移动");
}
}
class Dog extends Animal{
public void move(){
super.move();
sout("狗可以跑和走");
}
}
public class TestDog{
public static void main(String args[]){
Animal b = new Dog();
b.move();
}
}
运行结果:
动物可以移动
狗可以跑和走
重载
重载是在一个类里面,方法名字相同,而参数不同,返回类型可以相同也可以不同
每个重载的方法(或者构造函数)都必须有一个独一无二的参数类型列表
重载规则:
- 被重载的方法必须改变参数列表
- 被重载的方法可以改变返回类型
- 被重载的方法可以改变访问修饰符
- 被重载的方法可以声明新的或更广的检查异常
- 方法能够在同一个类中或者在一个子类中被重载
- 无法以返回值类型作为重载函数的区分标准
重写和重载的区分
重写 bark(方法名和参数都一样)
class Dog{
public void bark(){
sout("woof ");
}
}
class Hound extends Dog{
public void sniff(){
sout("sniff ");
}
public void bark(){
sout("bowl");
}
}
重载 bark(方法名相同,参数不同)
class DOg{
public void bark(){
sout("woof ");
}
public void bark(int num){
for(int i = 0; i < num; i++){
sout("woof ");
}
}
}
区别点 | 重载方法 | 重写方法 |
---|---|---|
参数列表 | 必须修改 | 一定不能修改 |
返回类型 | 可以修改 | 一定不能修改 |
异常 | 可以修改 | 可以减少或删除,一定不能抛出新的或更广的异常 |
访问 | 可以修改 | 一定不能做更严格的限制(可以降低限制) |
Java多态
多态是同一种行为具有不同表现形式或形态的能力
多态性是对象多种表现形式的体现
宠物=小猫+小狗+蜥蜴
public interface Vegetarian{}
public class Animal{}
public class Deer extends Animal implements Vegetarian{}
当我们将引用型变量应用于Deer对象的引用
Deer d = new Deer();
Animal a = d;
Vegetarian v = d;
Object o = d;
所有的引用型变量d,a,v,o都指向堆中想通的Deer对象
多态的实现方式
- 重写
- 接口
- 抽象类和抽象方法
Java抽象类
在Java面向对象的概念中,所有的对象都是通过类来秒回的
如果一个类中没有包含足够的信息来描绘一个具体的对象,这样的类就是抽象类
抽象类除了不能实例化对象之外,类的其他功能依旧存在:成员变量、成员方法、构造方法
由于抽象类不能实例化对象,所以抽象类必须被继承,才能被使用(通常在设计阶段决定要不要设计抽象类)
抽象方法
如果你想设计一个类:包含一个特别的成员方法,该方法的具体实现由它的子类确定,那么你可以在父类中声明该方法为抽象方法。
Abstract关键词同样可以声明抽象方法,抽象方法只包含一个方法名,没有方法体
抽象方法没有定义,方法名后面直接跟一个分号,而不是花括号
public abstract class Employee{
private String name;
private String address;
private int number;
public abstract double computePay();
//其余代码
}
声明抽象方法会造成以下两个结果:
- 如果一个类包含抽象方法,那么这个类必须是抽象类
- 任何子类必须重写父亲的抽象方法,或者声明自身为抽象类
继承抽象方法的子类必须重写该方法。否则子类也必须声明为抽象类。最终,必须有子类实现该抽象方法,否则,从最初的父类到最终的子类都不能用来实例化
如果Salary类继承了Employee类,那么它必须实现computePay()方法
public class Salary extends Employee{
private double salary;
public double computePay(){
sout("Computing salary pay for " + getName());
return salary/52;
}
}
Java封装
封装是一种将抽象性函式接口的实作细节部分包装、隐藏起来的方法
封装可以被认为是一个保护屏障,防止该类的代码和数据被外部类定义的代码随机访问
要访问该类代码和数据,必须通过严格的接口控制
封装最主要的功能在于我们能修改自己的实现代码,而不用修改那些调用我们代码的程序片段
适当的粉装可以让代码更容易理解和维护,也增强了代码的安全性
public class EncapTest{
private String name;
private String idNum;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getIdNum() {
return idNum;
}
public void setIdNum(String idNum) {
this.idNum = idNum;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
public方法是外部类访问该类成员变量的入口,这些方法称为getter和setter方法
因此,任何要访问类中私有成员变量的类都要通过这些getter和setter方法
public class RunEncap{
public static void main(String args[]){
EncapTest encap = new EncapTest();
encap.setName("James");
encap.setAge(20);
encap.setIdNum("12343ms");
sout("Name : " + encap.getName()
+ "Age: " + encap.getAge());
}
}
运行结果:
Name : James Age : 20