LOADING...

加载过慢请开启缓存(浏览器默认开启)

loading

Java日期+方法+文件流+scanner+异常+继承+重写载+多态+抽象+封装

2022/4/30 后端

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);
  • GregorianCalendar类

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()**方法获取输入的字符串

在读取前我们需要使用 hasNexthasNextLine 判断是否还有输入数据。

使用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中,类的继承是单一继承,一个子类只能拥有一个父类。

继承中最常使用的两个关键词是extendsimplements

这两个关键字的使用决定了一个对象和另一个对象是否是一个关系,我们能实现一个对象获取另一个对象的属性

所有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