leo_logic

Java回顾
一、Java语言体系&Java构成回顾Java SE 部分,Java 的标准版本。它包括Java最基础的一些结构,...
扫描右侧二维码阅读全文
15
2018/12

Java回顾

一、Java语言体系&Java构成回顾

Java SE 部分,Java 的标准版本。它包括Java最基础的一些结构,包括面向对象的一些特性等等,同时它也是 Java 技术基础和核心。
Java EE(Java 的企业版,在Java EE的基础上),应用于大型企业级应用的开发。
Java ME 主要用于嵌入式开发。初学的时候我们都是从 Java SE 开始的。

TIM截图20181215105954.png

JVM 叫 Java 虚拟机,它也是整个 Java 技术的核心。Java 语言的跨平台就多亏了 JVM。
JDK 叫 Java 开发工具包,没有 JDK 就没有办法进行 Java 程序的开发。
JRE 叫 Java 运行环境,如果我们需要运行一个Java程序,就得安装 JRE。
JDK、JRE和JVM之间的关系:
123456789.png

二、Java相关操作

1.版本查询和环境配置回顾
查询Java版本:java -version
补充:
配置环境变量。一般来说,我们会配置这三个环境变量:

JAVA_HOME 配置 JDK 安装路径
PATH 配置 JDK 命令文件的位置
**CLASSPATH 配置类库文件的位置(*之前学习中老师没提到过)**
配置CLASSPATH变量方法:
1.点击系统变量下的新建
2.变量名填CLASSPATH
3.变量值填JAVA的class路径与lib库路径(若是默认安装路径,打开计算机->C盘->Program Files->Java->jdk1.8.0_191(或者其他版本)->lib目录,拷贝路径就可以了),注意点击确定
 检测环境变量是否配置成功:javac、java都执行看看

2.eclipse使用相关回顾
创建包的目的:是便于我们对源代码的管理。
3.源码重回顾

public class HelloWorld
{
    public static void main(String[] args)
    {
        System.out.println("Hello World!");
    }
}
//public是类修饰,表示公有,class是关键字类 ,HelloWorld是类名,类名一定要与 Java 文件名一致;
//内部是一个main方法,是一个程序执行入口方法,方法上的public也是修饰,表示公有,static是静态修饰关键字,是类的一部分,不是对象的一部分,void是方法返回值,标识返回空,Java 必须用对象去调用方法,所以程序的入口方法是静态的;
//main是方法名,特殊方法,表示执行入口,括号里的String args[] 是方法参数,这里是指字符串数组,用来初始化程序;

三、Java程序构成

1.Java对象与方法
一个Java程序可以认为是一系列对象的集合,而这些对象通过调用彼此的方法来协同工作。

对象(object):对象是类的一个实例,有状态和行为。例如,一条狗是一个对象,它的状态有:颜色、名字、品种;行为有:摇尾巴、叫、吃等。
类(class):类是一个模板,它描述一类对象的行为和状态。
方法(method):方法就是行为,一个类可以有很多方法。逻辑运算、数据修改以及所有动作都是在方法中完成的。
实例变量:每个对象都有独特的实例变量,对象的状态由这些实例变量的值决定。
下面两点有关 Java 的书写方式:
Java 中的语句要以;结尾 。
用花括号{}来整合语句,形成程序块。通过程序块,我们可以知道程序的不同部分的范围,比如类从哪里开始,到哪里结束。

2.Java标识符:

  • Java 语言中,类、变量、常量、方法都需要名字,我们统统称之为 Java 标识符.
  • 标识符是用来给类、对象、方法、变量、接口和自定义数据类型命名的。
  • 关于 Java 标识符,有几点需要注意的:

    Java 标识符由数字,字母A-Z或者a-z和下划线_,美元符号$组成。
    所有的标识符都应该以字母A-Z或者a-z,美元符$、或者下划线_开始,首位不能是数字。
    关键字不能用作标识符。
    在 Java 中是区分大小写的。

    3.Java常见命名规则:

  • 在 Java 中,还有一些约定俗成的命名规则,希望同学们在写代码的时候都能遵循这些规则:

    ①类和接口名。每个字的首字母大写,含有大小写。例如,MyClass,HelloWorld,Time 等。
    ②方法名。首字符小写,其余的首字母大写,含大小写。尽量少用下划线。例如,myName,setTime 等。这种命名方法叫做驼峰式命名。
    ③常量名。基本数据类型的常量名使用全部大写字母,字与字之间用下划线分隔。对象常量可大小混写。例如,SIZE_NAME。
    ④变量名。可大小写混写,首字符小写,字间分隔符用字的首字母大写。不用下划线,少用美元符号。给变量命名是尽量做到见名知意。
    ⑤命名过程中尽量做到见名知意,方便后期查看和修改代码,也方便其他人员的阅读。
    

4.Java中主要有如下几种类型的变量:(在Java中,所谓的变量实际上是基本类型 (premitive type)。)

局部变量
类变量(静态变量)
成员变量(非静态变量)

5.Java的注释
一般在 Java 里有三种注释:

行注释//:只注释一行
段注释/*...*/:注释若干行
文档注释/**...*/:注释若干行,并写入 javadoc文档
自动类型转换需要满足下面的两个条件:
目标类型与原类型兼容
目标类型的字节数大于或等于原类型字节数
基本数据类型中,由于布尔类型其本身所代表的特殊含义,不能与其他基本类型进行类型的转换(既不能进行自动类型的提升,也不能强制类型转换), 否则,将编译出错。

6.运算部分注意点

①自增(++)和自减(--)运算符有两种写法:前缀(++i,--i)和后缀(i++,i--)。
    前缀自增自减法(++i,--i): 先进行自增或者自减运算,再进行表达式运算。
    后缀自增自减法(i++,i--): 先进行表达式运算,再进行自增或者自减运算
②位运算
    Java定义了位运算符,应用于整数类型(int),长整型(long),短整型(short),字符型(char),和字节型(byte)等类型。位运算时先转换为二进制,再按位运算。
③赋值运算`+=    加等于    左操作数和右操作数相加赋值给左操作数    双目运算符    a += c等价于a = a + c`
④关系运算: ==和!=适用于所有的基本数据类型,其他关系运算符不适用于boolean,因为boolean值只有true和false,比较没有任何意义。  
           ==和!=也适用于所有对象,可以比较对象的引用是否相同。
引用:Java 中一切都是对象,但操作的标识符实际是对象的一个引用。
           而想要比较对象的内容是否相同时,Java 提供了一个特殊的方法equals(),它不适用于基本类型,基本类型使用==和!=进行比较。
注意:但是当自己创建了一个类时,情况又会相反,因为equals()默认比较引用,除非在自己的类中覆盖equal()方法。

6.Java控制语句

①if条件控制语句:所有的条件语句都是利用条件表达式的真或假来决定执行路径,Java里不允许将一个数字作为布尔值使用,虽然这在C和C++是允许的,如果要在布尔测试里使用一个非布尔值,需要先用一个条件表达式将其转换成布尔值,其他控制语句同理。
②while 的执行过程是先判断,再执行。do-while 的执行过程是先执行,再判断(所以循环内的代码至少会执行一次)
③continue跟break跳转语句
break的意思为跳出 //经常用在条件和循环语句中,用来跳出循环语句的。
continue;  //通过continue结束本次循环

四、Java数组

数组对于每一门编程语言来说都是重要的数据结构之一,在Java中,数组是一种效率最高的存储和随机访问对象引用序列的方式,它被用来存储固定大小的同类型元素。

  • 数组就是相同数据类型的元素按一定顺序排列的集合。我们可以把它看成一个大的盒子,里面按顺序存放了多个数据类型相同的数据。
  • 数组下标从 0 开始。所以数组的下标范围是0 至 数组长度-1。数组不能越界访问,否则会报错。
    数组声明:
    数据类型[ ] 数组名;   //或者: 数据类型 数组名[ ];
    int ages[];      //存放年龄的数组,类型为整型
    char symbol[];   //存放符号的数组,类型为字符型
    String [] name;  //存放名称的数组,类型为字符串型
    当我们声明了数组后,需要为数组分配空间,也就是定义多大的数组。
    语法:
    数组名 = new  数据类型 [ 数组长度 ];
    数组长度就是数组最多可存放元素的个数。我们也可以在数组声明的时候初始化数组,或者在声明时就为它分配好空间,这样我们就可以不用再为数组分配空间。

语法:

    int [] ages = {12,18,9,33,45,60}; //声明并初始化了一个整型数组,它有6个元素
    char [] symbol = new char[10] //声明并分配了一个长度为10的char型数组

数组间赋值:

    int [] a1 = {1,2,3};
    int [] a2;
    a2 = a1;
    /*
      以上Java数组间赋值,实际是赋值的指向地址
      测试方法:修改a2的值会发现a1的值发生变化
    */

for 语句在数组内可以使用特殊简化版本,在遍历数组、集合时,foreach 更简单便捷。从英文字面意思理解 foreach 也就是“ for 每一个”的意思。

for(元素类型 元素变量:遍历对象){
    执行的代码
}

二维数组也需要声明和分配空间。
语法:

数据类型 [][] 数组名 = new 数据类型[行的个数][列的个数];

//或者
数据类型 [][] 数组名;
数组名 = new 数据类型[行的个数][列的个数];

//也可以
数据类型 [][] 数组名 = {
{第一行值1,第一行值2,...}
{第二行值1,第二行值2,...}
...
}

//二维数组的赋值和访问,跟一维数组类似,可以通过下标来逐个赋值和访问,注意索引从 0 开始
数组名行的索引 = 值;
例子:

String [][] name = {{"ZhaoYi", "QianEr", "SunSan"},
            {"LiSi", "ZhouWu", "WuLiu"}};
    for(int i = 0; i < 2; i++){
        for (int j = 0; j < 3; j++){
            System.out.println(name[i][j] );
        }
    }

例子:

public class testT {
    public static void main(String[] args){
    int num[][] = new int[5][3];  //---定义了一个整型的二维数组,其中包含5个一维数组,每个一维数组可以存储8个整数
    int count = 0;
    for(int i = 0; i < 5; i++){
        for(int j = 0; j < 7; j++){
            num[i][j] = ++count;
            System.out.printf("%3d ",num[i][j]);
        }
        System.out.println();
    }
}
}
//arr[0]---下标为0的位置上的一维数组
//arr[1][4]---如果要获取具体的元素需要两个下标

我们创建一个类需要它来继承某一个类的语法:

五、方法

Java中的方法,我们可以将其看成一个功能的集合。

println() 是一个方法
System 是系统类
out 是标准输出对象
这句语句的意思是调用系统类 System 中的标准输出对象 out 中的方法 println()。
  • 方法的定义语法:
    访问修饰符 返回值类型 方法名(参数列表){

    方法体

    }
    访问修饰符:代表方法允许被访问的权限范围, 可以是 public、protected、private 甚至可以省略 ,其中 public 表示该方法可以被其他任何代码调用
    返回值类型:方法返回值的类型,如果方法不返回任何值,则返回值类型指定为 void (代表无类型);如果方法具有返回值,则需要指定返回值的类型,并且在方法体中使用 return 语句返回值。
    参数列表:是传递给方法的参数列表,参数可以有多个,多个参数间以逗号隔开,每个参数由参数类型和参数名组成,以空格隔开。当方法被调用时,传递值给参数。这个值被称为实参或变量。参数列表是指方法的参数类型、顺序和参数的个数。参数是可选的,方法可以不包含任何参数。
    方法体:方法体包含具体的语句,定义该方法的功能。
    ①简单方法的呈现
    public class PrintScore {

    public static void main(String[] args) {
    
        // 创建对象,对象名为a
        PrintScore a = new PrintScore();
    
        int rSum;  //设置一个int型变量,用来接收方法的返回值
    
        // 调用方法,传入两门课程的成绩
        rSum = a.calcSum(78,99);
        System.out.println("总分:"+ rSum);
    }
    
    /*
     * 功能:计算两门课程考试成绩的总分并输出总分
     * 定义一个包含两个参数的方法,用来传入两门课程的成绩
     */
    public int calcSum(int a, int b){ //方法名为calcSum,修饰符publc,返回值,方法名主要在调用这个方法时使用,需要注意命名的规范,一般采用第一个单词首字母小写,其它单词首字母大写的形式
            int sum= a + b;
            return sum;
    }
    

    }
    ②形参与实参:形参仅作用于方法中,在方法的参数位置,即括号里
    public class PrintScore {

    public static void main(String[] args) {
    
        // 创建对象,对象名为a
        PrintScore a = new PrintScore();
    
        int rSum;  //设置一个int型变量,用来接收方法的返回值
    
        // 调用方法,传入两门课程的成绩
        rSum = a.calcSum(78,99);
        System.out.println("总分:"+ rSum);
    }
    
    /*
     * 功能:计算两门课程考试成绩的总分并输出总分
     * 定义一个包含两个参数的方法,用来传入两门课程的成绩
     */
    public int calcSum(int a, int b){ //方法名为calcSum,修饰符publc,返回值,方法名主要在调用这个方法时使用,需要注意命名的规范,一般采用第一个单词首字母小写,其它单词首字母大写的形式
            int sum= a + b;
            return sum;
    }
    /*
    调用带参方法时,必须保证实参的数量、类型、顺序与形参一一对应
    调用方法时,实参不需要指定数据类型
    当方法参数有多个时,多个参数间以逗号分隔
    */
    

    }
    ③方法重载:

在Java中通过在类中写多个方法,这类方法的方法名相同,方法的参数列表不同(参数的个数和参数类型的不同)来实现方法的重载。所谓方法重载就是:在一个类中,有一系列的方法具有方法名相同,但参数列表不同,这类方法的实现就是方法重载。

public class Test {
    void f(int i) {
        System.out.println("i=" + i);
    }

    void f(float f) {
        System.out.println("f=" + f);
    }

    void f(String s) {
        System.out.println("s=" + s);
    }

    void f(String s1, String s2){
        System.out.println("s1+s2="+(s1+s2));
    }

    void f(String s, int i){
        System.out.println("s="+s+",i="+i);
    }

    public static void main(String[] args) {
        Test test = new Test();
        test.f(3456);
        test.f(34.56f);
        test.f("abc");
        test.f("abc","def");
        test.f("abc",3456);
    }
}

在进行方法重载的时候需要遵循以下的规则:

在使用方法重载的时候,必须通过方法中不同的参数列表来实现方法的重载。如:方法的参数个数不同或者方法的参数类型不同。
不能通过访问权限,返回值类型和抛出的异常来实现重载
重载的方法中允许抛出不同的异常
可以有不同的返回值类型,只要方法的参数列表不同即可
可以有不同的访问修饰符

④返回值:
如果方法的返回类型为 void ,则方法中不能使用 return 返回值。
方法的返回值最多只能有一个,不能返回多个值。
方法返回值的类型必须兼容,也就是说如果返回值类型为 int ,则不能返回 String 型值
调用带返回值的方法时,由于方法执行后会返回一个结果,因此在调用带返回值方法时一般都会接收其返回值并进行处理
⑤什么是对象?
1)从字面意思来看就是我们面对的物象。
2)从这个对象的整体出发去看它,它由哪些部件组成,它可以做到哪些事情。
3)对象一定是一个具体的、确定的物体。
4)这部手机的“属性”,这部手机可以打电话、发短信,便是它的“行为”。
面向对象的思想,体现的是人所关注对象的信息聚集在了一个具体的物体上。人们就是通过对象的属性和行为来了解对象。
⑥什么是类?
具有相同属性和行为的一类实体被称为类。
由此我们可以总结出类的定义:

类是相同或相似对象的一种抽象,是对象的一个模板,它描述一类对象的行为和状态。
类是具有相同属性和方法(行为)的对象的集合

属性:对象具有的特征。每个对象的每个属性都拥有特定值。我们上面讲过对象是一个具体并且确定的事物,正是对象属性的值来区分不同的对象,比如我们可以通过一个人的外貌特征区分他。
对象的行为:在计算机中我们通过方法去实现对象的行为,而对象的方法便是对象所具有的操作,比如人会走路。

public class 类名{
//定义属性部分(成员变量)
属性1的类型 属性1;
属性2的类型 属性2;
...
//定义方法部分
方法1;
方法2;
...
}

一个类可以包含以下类型变量:

局部变量:在方法、构造方法或者语句块中定义的变量被称为局部变量。变量声明和初始化都是在方法中,方法结束后,变量就会自动销毁。
成员变量:成员变量是定义在类中,方法体之外的变量。这种变量在创建对象的时候实例化。成员变量可以被类中方法、构造方法和特定类的语句块访问。
类变量:也叫静态变量,类变量也声明在类中,方法体之外,但必须声明为static类型。
局部变量的作用域仅限于定义它的方法内。而成员变量的作用域在整个类内部都是可见的。
同时在相同的方法中,不能有同名的局部变量;在不同的方法中,可以有同名的局部变量。
成员变量和局部变量同名时,局部变量具有更高的优先级。 大家可以编写代码验证一下。
  • 匿名内部类
    匿名内部类,顾名思义,就是没有名字的内部类。正因为没有名字,所以匿名内部类只能使用一次,它通常用来简化代码编写。但使用匿名内部类还有个前提条件:必须继承一个父类或实现一个接口。

匿名内部类是不能加访问修饰符的。要注意的是,new 匿名类,这个类是要先定义的,如果不先定义,编译时会报错该类找不到。
同时,在上面的例子中,当所在的方法的形参需要在内部类里面使用时,该形参必须为final。这里可以看到形参 name 已经定义为final了,而形参city 没有被使用则不用定义为final。
然而,因为匿名内部类没名字,是用默认的构造函数的,无参数的,如果需要该类有带参数的构造函数。

public class Outer {

    public Inner getInner(final String name, String city) {
        return new Inner() {
            private String nameStr = name;
            public String getName() {
                return nameStr;
            }
        };
     }
    //    public Inner getInner(final String name, String city) {
    //     return new Inner(name, city) {
    //         private String nameStr = name;
    //         public String getName() {
    //             return nameStr;
    //         }
    //     };
    // }
    public static void main(String[] args) {
        Outer outer = new Outer();
        Inner inner = outer.getInner("Inner", "NewYork");
        System.out.println(inner.getName());
    }
}
interface Inner {
    String getName();
}

注意这里的形参city,由于它没有被匿名内部类直接使用,而是被抽象类Inner的构造函数所使用,所以不必定义为final。


面向对象
封装:
也就是把客观事物封装成抽象的类,并且类可以把自己的数据和方法只让可信的类或者对象操作,对不可信的进行信息隐藏。封装是面向对象的特征之一,是对象和类概念的主要特性。 简单的说,一个类就是一个封装了数据以及操作这些数据的代码的逻辑实体。在一个对象内部,某些代码或某些数据可以是私有的,不能被外界访问。通过这种方式,对象对内部数据提供了不同级别的保护,以防止程序中无关的部分意外的改变或错误的使用了对象的私有部分。

继承:
是指可以让某个类型的对象获得另一个类型的对象的属性的方法。它支持按级分类的概念。继承是指这样一种能力:它可以使用现有类的所有功能,并在无需重新编写原来的类的情况下对这些功能进行扩展。 通过继承创建的新类称为“子类”或“派生类”,被继承的类称为“基类”、“父类”或“超类”。继承的过程,就是从一般到特殊的过程。要实现继承,可以通过“继承”(Inheritance)和“组合”(Composition)来实现。继承概念的实现方式有二类:实现继承与接口继承。实现继承是指直接使用基类的属性和方法而无需额外编码的能力;接口继承是指仅使用属性和方法的名称、但是子类必须提供实现的能力;

多态:
就是指一个类实例的相同方法在不同情形有不同表现形式。多态机制使具有不同内部结构的对象可以共享相同的外部接口。这意味着,虽然针对不同对象的具体操作不同,但通过一个公共的类,它们(那些操作)可以通过相同的方式予以调用。

六、封装

1.封装是指,一种将抽象性函式接口的实例细节部份包装、隐藏起来的方法。封装可以被认为是一个保护屏障,防止该类的代码和数据被外部类定义的代码随机访问。要访问该类的代码和数据,必须通过严格的接口控制,通过该类提供的方法来实现对隐藏信息的操作和访问。

①只能通过规定的方法访问数据
②隐藏类的实例细节,方便修改和实现。
实现类的封装:
①修改属性的可见性,在属性的前面添加修饰符(private 后面会讲)
②对每个值属性提供对外的公共方法访问,如创建 getter/setter(取值和赋值) 方法,用于对私有属性的访问
③在 getter/setter 方法里加入属性的控制语句,例如我们可以加一个判断语句,对于非法输入给予否定。
public class People {
//属性(成员变量)有什么,前面添加了访问修饰符private
//变成了私有属性,必须通过方法调用
    private double height;     //身高

//属性已经封装好了,如果用户需要调用属性
//必须用getter和setter方法进行调用
//getter和setter方法需要程序员自己定义
    public double getHeight(){    
    //getter 方法命名是get关键字加属性名(属性名首字母大写)
    //getter 方法一般是为了得到属性值
        return height;
    }

//同理设置我们的setter方法
//setter 方法命名是set关键字加属性名(首字母大写)
//setter 方法一般是给属性值赋值,所以有一个参数
    public void setHeight(double newHeight){
        height = newHeight;
    }
}

2.包:有时候在封装的时候会遇到这样的问题,就是我们的类名可能是重复的。为了更好地组织类,Java 提供了包机制,用于区别类名的命名空间。
包的作用:
①把功能相似或相关的类或接口组织在同一个包中,方便类的查找和使用。
②包采用了树形目录的存储方式。同一个包中的类名字是不同的,不同的包中的类的名字是可以相同的,当同时调用两个不同包中相同类名的类时,应该加上包名加以区别。
③包也限定了访问权限,拥有包访问权限的类才能访问某个包中的类。
我们在以前就学习过了如何定义一个包,我们使用package关键字,加上我们的包名。
在不同包中使用另一个文件中的类呢?这时候就需要用到import关键字。比如我们要导入包com.shiyanlou下People这个类。import com.shiyanlou.People,同时如果import com.shiyanlou.这是将包下的所有文件都导入进来,是通配符。
3.访问修饰符:
TIM截图20181218194130.png

private修饰的属性或者方法,只能在当前类中访问或者使用。默认是什么修饰符都不加,默认在当前类中和同一包下都可以访问和使用。protected修饰的属性或者方法,对同一包内的类和所有子类可见。public修饰的属性或者方法,对所有类可见。
用private修饰代表着这是私有的,只能我自己可以使用。如果是protected代表着我可以使用,和我有关系的人,比如儿子也可以用。如果是public就代表了所有人都可以使用。

4.this关键字:
this关键字代表当前对象。使用this.属性操作当前对象的属性,this.方法调用当前对象的方法。

5.成员内部类

//外部类People
public class People {
    private String name = "LiLei";         //外部类的私有属性
    //内部类Student
    public class Student {
        String ID = "20151234";               //内部类的成员属性
        //内部类的方法
        public void stuInfo(){
            System.out.println("访问外部类中的name:" + name);
            System.out.println("访问内部类中的ID:" + ID);
        }
    }

    //测试成员内部类
    public static void main(String[] args) {
        People a = new People();     //创建外部类对象,对象名为a
        Student b = a.new Student(); //使用外部类对象创建内部类对象,对象名为b
        // 或者为 People.Student b = a.new Student();
        b.stuInfo();   //调用内部对象的suInfo方法
    }
}

成员内部类的使用方法:

Student 类相当于 People 类的一个成员变量,所以 Student 类可以使用任意访问修饰符
Student 类在 People 类里,所以访问范围在类里的所有方法均可以访问 People 的属性(即内部类里可以直接访问外部类的方法和属性,反之不行)
定义成员内部类后,必须使用外部类对象来创建内部类对象,即 内部类 对象名 = 外部类对象.new 内部类();
如果外部类和内部类具有相同的成员变量或方法,内部类默认访问自己的成员变量或方法,如果要访问外部类的成员变量,可以使用 this 关键字 如上述代码中:a.this
  1. 静态内部类
    静态内部类通常被称为嵌套类。
    //外部类People
    public class People {

    private String name = "LiLei";         //外部类的私有属性
    

    /*外部类的静态变量。
    Java 中被 static 修饰的成员称为静态成员或类成员。它属于整个类所有,而不是某个对象所有,即被类的所有对象所共享。静态成员可以使用类名直接访问,也可以使用对象名进行访问。
    */

    static String ID = "510xxx199X0724XXXX"; 
    
    //静态内部类Student
    public static class Student {
        String ID = "20151234";               //内部类的成员属性
        //内部类的方法
        public void stuInfo(){
            System.out.println("访问外部类中的name:" + (new People().name));
            System.out.println("访问外部类中的ID:" + People.ID);
            System.out.println("访问内部类中的ID:" + ID);
        }
    }
    
    //测试成员内部类
    public static void main(String[] args) {
        Student b = new Student();   //直接创建内部类对象,对象名为b
        b.stuInfo();                 //调用内部对象的suInfo方法
    }

    }
    静态内部类是 static 修饰的内部类,这种内部类的特点是:
    静态内部类不能直接访问外部类的非静态成员,但可以通过 new 外部类().成员 的方式访问
    如果外部类的静态成员与内部类的成员名称相同,可通过类名.静态成员访问外部类的静态成员;如果外部类的静态成员与内部类的成员名称不相同,则可通过成员名直接调用外部类的静态成员
    创建静态内部类的对象时,不需要外部类的对象,可以直接创建 内部类 对象名= new 内部类();

  2. 局部内部类:
    局部内部类,是指内部类定义在方法和作用域内。
    局部内部类也像别的类一样进行编译,但只是作用域不同而已,只在该方法或条件的作用域内才能使用,退出这些作用域后无法引用的。
    例如:

    //外部类People
    public class People {

    //定义在外部类中的方法内:
    public void peopleInfo() {
        final String sex = "man";  //外部类方法中的常量
        class Student {
            String ID = "20151234"; //内部类中的常量
            public void print() {
                System.out.println("访问外部类的方法中的常量sex:" + sex);
                System.out.println("访问内部类中的变量ID:" + ID);
            }
        }
        Student a = new Student();  //创建方法内部类的对象
        a.print();//调用内部类的方法
    }
    //定义在外部类中的作用域内
    public void peopleInfo2(boolean b) {
        if(b){
            final String sex = "man";  //外部类方法中的常量
            class Student {
                String ID = "20151234"; //内部类中的常量
                public void print() {
                    System.out.println("访问外部类的方法中的常量sex:" + sex);
                    System.out.println("访问内部类中的变量ID:" + ID);
                }
            }
            Student a = new Student();  //创建方法内部类的对象
            a.print();//调用内部类的方法
        }
    }
    //测试方法内部类
    public static void main(String[] args) {
        People b = new People(); //创建外部类的对象
        System.out.println("定义在方法内:===========");
        b.peopleInfo();  //调用外部类的方法
        System.out.println("定义在作用域内:===========");
        b.peopleInfo2(true);
    }

    }

8.匿名内部类
匿名内部类,顾名思义,就是没有名字的内部类。正因为没有名字,所以匿名内部类只能使用一次,它通常用来简化代码编写。但使用匿名内部类还有个前提条件:必须继承一个父类或实现一个接口。
例如:

public class Outer { 

    public Inner getInner(final String name, String city) { 
        return new Inner() { 
            private String nameStr = name; 
            public String getName() { 
                return nameStr; 
            } 
        };
    } 

    public static void main(String[] args) { 
        Outer outer = new Outer(); 
        Inner inner = outer.getInner("Inner", "NewYork"); 
        System.out.println(inner.getName()); 
    } 
} 
interface Inner { 
    String getName(); 
}
运行结果:Inner

匿名内部类是不能加访问修饰符的。要注意的是,new 匿名类,这个类是要先定义的,如果不先定义,编译时会报错该类找不到。
同时,在上面的例子中,当所在的方法的形参需要在内部类里面使用时,该形参必须为final。这里可以看到形参 name 已经定义为final了,而形参city 没有被使用则不用定义为final。
然而,因为匿名内部类没名字,是用默认的构造函数的,无参数的,如果需要该类有带参数的构造函数,示例如下:

public Inner getInner(final String name, String city) { 
     return new Inner(name, city) { 
         private String nameStr = name; 

         public String getName() { 
                return nameStr; 
            } 
        }; 
} 

注意这里的形参city,由于它没有被匿名内部类直接使用,而是被抽象类Inner的构造函数所使用,所以不必定义为final。

七、面向对象_Java继承

我们创建一个类需要它来继承某一个类的语法:

    class 子类 extends 父类
    例如我们定义了一个 Animal 类,我们在创建一个 Dog 类,我们需要它继承 Animal 类
    class Dog extends Animal {
        ...
    }
    ①父类
    public class Animal {
        public int legNum;  //动物四肢的数量
        //类方法
        public void bark() {
            System.out.println("动物叫!");
        }
    }
    ②子类
    public class Dog extends Animal{
    
    }
    ③测试类
    public class Test{
        public static void main(String[] args) {
            Dog a = new Dog();
            a.legNum = 4;
            a.bark();
        }
    }

为什么需要继承?

如果有两个类相似,那么它们会有许多重复的代码,导致后果就是代码量大且臃肿,后期的维护性不高。通过继承就可以解决这个问题,将两段代码中相同的部分提取出来组成一个父类,实现代码的复用。

继承的特点:

子类拥有父类除private以外的所有属性和方法
子类可以拥有自己的属性和方法
子类可以重写实现父类的方法
Java 中的继承是单继承,一个类只有一个父类
注:Java 实现多继承的一个办法是**implements(实现)**接口

方法的重写?

当子类"不满意"父类的方法时,子类可以进行方法的重写

当然在方法重写时我们需要注意,重写的方法一定要与原父类的方法语法保持一致,比如返回值类型,参数类型及个数,和方法名都必须一致。
继承的初始化顺序是先初始化父类再初始化子类。

final关键字可以修饰类、方法、属性和变量
final 修饰类,则该类不允许被继承,为最终类
final 修饰方法,则该方法不允许被覆盖(重写)
final 修饰属性:则该类的属性不会进行隐式的初始化(类的初始化属性必须有值)或在构造方法中赋值(但只能选其一)
final 修饰变量,则该变量的值只能赋一次值,即变为常量
super关键字在子类内部使用,代表父类对象。
访问父类的属性 super.属性名
访问父类的方法 super.bark()
子类构造方法需要调用父类的构造方法时,在子类的构造方法体里最前面的位置:super()

由此可知,系统先创建父类对象,再创建了子类对象,先初始化属性,再调用了构造函数

八、面向对象_Java多态

(1)多态简介:
多态是指允许不同类的对象对同一消息做出响应。即同一消息可以根据发送对象的不同而采用多种不同的行为方式。多态也称作动态绑定(dynamic binding),是指在执行期间判断所引用对象的实际类型,根据其实际的类型调用其相应的方法。
通俗地讲,只通过父类就能够引用不同的子类,这就是多态,我们只有在运行的时候才会知道引用变量所指向的具体实例对象。
(2)向上转型:

package test;
class Animal {
    //父类方法
    public void bark() {
        System.out.println("动物叫!");
    }
}

class Dog extends Animal {

    //子类重写父类的bark方法
    public void bark() {
        System.out.println("汪、汪、汪!");
    }
    //子类自己的方法
    public void dogType() {
        System.out.println("这是什么品种的狗?");
    }
}


public class Test {

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

        a.bark();
        b.bark();
        //b.dogType(); 
        /*b.dogType()编译不通过&这个地方是重点在这里,由于b是父类的引用,指向子类的对象,因此不能获取子类的方法(dogType()方法),同时当调用bark()方法时,由于子类重写了父类的bark()方法,所以调用子类中的bark()方法。
*/
        d.bark();
        d.dogType();
    }
}
**因此,向上转型,在运行时,会遗忘子类对象中与父类对象中不同的方法,也会覆盖与父类中相同的方法——重写。(方法名,参数都相同)**

(3)多态的实现条件:

Java 实现多态有三个必要条件:继承、重写和向上转型(即父类引用指向子类对象)。
只有满足上述三个条件,我们才能够在同一个继承结构中使用统一的逻辑实现代码处理不同的对象,从而达到执行不同的行为。

(4)多态的实现方式:

Java中多态的实现方式:继承父类进行方法重写,抽象类和抽象方法,接口实现。

1)重写
2)抽象类和抽象方法:
Java提供了一个叫做抽象方法的机制,这种方法是不完整的,仅有声明而没有方法体。抽象方法声明语法如下:
abstract void f(); //f()方法时抽象方法
抽象类是限制子类的必须实现某些方法,但并不关注实现细节
那抽象类如何用代码实现呢,它的规则如下:

①用 abstract 修饰符定义抽象类
②用 abstract 修饰符定义抽象方法,只用声明,不需要实现
③包含抽象方法的类就是抽象类
④抽象类中可以包含普通的方法,也可以没有抽象方法
⑤抽象类的对象不能直接创建,我们通常是定义引用变量指向子类对象。也从具体和抽象的关系去理解,具体的事物是实时存在

的,而抽象的东西需要人们去生产加工得到实体
3)构建子类(通过继承),实现抽象类的方法
e.g.

package test;
//抽象方法,父类
public abstract class TelePhone {
  public abstract void call();  //抽象方法,打电话
  public abstract void message(); //抽象方法,发短信
}
package test;
//抽象方法,子类
public class CellPhone extends TelePhone {

    @Override
    public void call() {
        System.out.println("我可以打电话!");
    }

    @Override
    public void message() {
        System.out.println("我可以发短信!");
        System.out.println("我可以睡觉!");
    }

    public static void main(String[] args) {
        CellPhone cp = new CellPhone();
        cp.call();
        cp.message();
    }

}

(5) 接口实现
abstract 关键字允许人们在类中创建一个或多个没有任何定义的方法,而 interface 使抽象的概念更向前迈进了一步。
接口的声明语法格式如下:
接口声明方法:

修饰符 interface 接口名称 [extends 其他的类名] {
        // 声明变量
        // 抽象方法
}

如声明一个animal接口:

interface Animal {
        //int x;
        //编译错误,x需要初始化,因为是 static final 类型
        int y = 5;
        public void eat();
        public void travel();
}

在Java8中:

接口不能用于实例化对象
接口中方法只能是抽象方法、default方法、静态方法
接口成员是 static final 类型
接口支持多继承

在Java9中,接口可以拥有私有方法私有静态方法。default方法和静态方法可以使用它们。
多继承方法:

修饰符 interface A extends 接口1,接口2{
}
修饰符 class A implements 接口1,接口2{
} 
public class Cat implements Animal{
     public void eat(){
         System.out.println("Cat eats");
     }
     public void travel(){
         System.out.println("Cat travels");
     }
     public static void main(String[] args) {
        Cat cat = new Cat();
        cat.eat();
        cat.travel();
    }
}

九、异常处理

异常是什么?为什么要处理?

  • 在真实的程序运行过程中,诸如除0溢出、数组越界、文件找不到等错误的发生,将阻止程序的正常运行。而在Java世界里,这些错误我们通常称之为异常。
  • 本次实验我们将学习Java中的异常机制,观察程序中的错误是如何发生并解决的,你还有机会自己动手定义异常类。
    处理程序异常的意义:之所以要处理异常,也是为了增强程序的鲁棒性(鲁棒是Robust的音译,也就是健壮和强壮的意思。它是在异常和危险情况下系统生存的关键)。一个程序不稳定导致用户丢失数据,那么很高几率上用户不会在使用这款软件了。

(1)常见异常:
1)异常都是从Throwable类派生出来的,而Throwable类是直接从Object类继承而来。
异常通常有四类:

①Error:系统内部错误,这类错误由系统进行处理,程序本身无需捕获处理
②Exception:可以处理的异常
③RuntimeException:可以捕获,也可以不捕获的异常
④继承Exception的其他类:必须捕获,通常在API文档中会说明这些方法抛出哪些异常

2)算术异常:
①算数运算

package ariException;
public class AriExceptionTest {
    public static void main(String[] args) {
        System.out.println("Example 1:  -1.0 / 0 = " + (-1.0 / 0));
        // 演示负浮点数除0

        System.out.println("Example 2:  +1.0 / 0 = " + (+1.0 / 0));
        // 演示正浮点数除0

        System.out.println("Example 3:  -1 / 0 = " + (-1 / 0));
        // 演示负整数除0

        System.out.println("Example 4:  +1 / 0 = " + (+1 / 0));
        // 演示正整数除0
    }
}

以上代码执行结果:
TIM截图20181220112735.png

可以看到,实际上程序在运行到Example 3的时候就已经出现了算数异常。当代码抛出一个异常的同时,也终止了对剩余代码的处理,所以Example 4根本没有机会执行。
这是由于在Java中,浮点数(无论是float还是double类型的浮点数)被0除,并不会引发算术异常。具体说来,是操作系统为了保护应用软件而已经处理了该异常,不再抛出,最终运算结果是无穷大。

3)数组下标越界异常(ArrayIndexOutOfBoundsException)
Java SE官方文档对于数组下标越界异常的定义是:

用非法索引访问数组时抛出的异常。如果索引为负或大于等于数组大小,则该索引为非法索引。
import java.util.Arrays;
public class ArrayExceptionTest {

    public static void main(String[] args) {
        int[] array = new int[5]; 
        // 声明一个长度为5的整型数组array

        Arrays.fill(array, 8); 
        // 将该数组所有元素赋值为8

        for (int i = 0; i < 6; i++) {
            // 用遍历的方式,输出所有数组元素,注意此处的控制条件 i < 6

            System.out.println("array[" + i + "] = " + array[i]);
            //下标将会增加到5,显然是超出了数组array的范围(0到4),程序将在第6次循环前抛出异常
        }
    }
}

以上代码执行结果:
shuzuyichang.png

不难看出程序将第6次循环前抛出异常

4)空指针异常(NullPointerException)

当应用程序试图在需要对象的地方使用 null 时,抛出该异常。这种情况包括:
调用 null 对象的实例方法。
访问或修改 null 对象的字段。
将 null 作为一个数组,获得其长度。
将 null 作为一个数组,访问或修改其时间片。
将 null 作为 Throwable 值抛出。
应用程序应该抛出该类的实例,指示其他对 null 对象的非法使用。

示例代码:

public class NullPointerExceptionTest {
    public static void main(String[] args) {
        String s= null;
        // 将字符串设置为null
        System.out.println(s.toUpperCase());
        // 尝试将字符串转换成大写,看看会发生什么
    }
}

参考图片:
NULlyichang.png

除了上述3种,异常的种类还有很多很多,比如IllegalAccessException、FileNotFoundException以及在操作数据库时抛出的异常,你可以在API文档中查看它们的产生原因。Java SE的API已经为我们提供了数十种异常类,除了这些我们可以自定义异常类信息。

(2)自定义异常类:
自定义一个异常类非常简单,只需要让它继承Exception或其子类就行。在自定义异常类的时候,建议同时提供无参构造方法和带字符串参数的构造方法,后者可以为你在调试时提供更加详细的信息。
①MyAriException.java文件中代码如下:

public class MyAriException extends ArithmeticException {            
    //自定义异常类,该类继承自ArithmeticException

    public MyAriException() {

    }
    //实现默认的无参构造方法

    public MyAriException(String msg) {
        super(msg);
    }
    //实现可以自定义输出信息的构造方法,将待输出信息作为参数传入即可
}

②ExceptionTest.java文件中代码如下:

public static void main(String[] args) {
    int[] array = new int[5];
    //声明一个长度为5的数组

    Arrays.fill(array, 5);
    //将数组中的所有元素赋值为5

    for (int i = 4; i > -1; i--) {
        //使用for循环逆序遍历整个数组,i每次递减

        if (i == 0) {
        // 如果i除以了0,就使用带异常信息的构造方法抛出异常

            throw new MyAriException("出现了一个异常");
        }

        System.out.println("array[" + i + "] / " + i + " = " + array[i] / i);
        // 如果i没有除以0,就输出此结果
    }
}

}

(3)捕获异常:
当我们在编程时遇到了异常不要紧,除了可以将异常抛出,还可以将异常捕获。通常使用trycatch语句块来捕获异常,有时候还会用到finally
对于上述三个关键词所构成的语句块,try语句块是必不可少的,catchfinally语句块可以根据情况选择其一或者全选。你可以把可能发生错误或出现问题的语句放到try语句块中,将异常发生后要执行的语句放到catch语句块中,而finally语句块里面放置的语句,不管异常是否发生,它们都会被执行。
不要将代码全都放入try内,捕获异常对于系统而言,其开销非常大,所以应尽量减少该语句块中放置的语句。

建类CatchException,添加下面的关键代码:

public class CatchException {
    public static void main(String[] args) {
        try {
            // 下面定义了一个try语句块

            System.out.println("I am try block.");

            Class<?> tempClass = Class.forName("");    
            // 声明一个空的Class对象用于引发“类未发现异常”
            System.out.println("Bye! Try block.");

        } catch (ClassNotFoundException e) {
            // 下面定义了一个catch语句块
            System.out.println("I am catch block.");

            e.printStackTrace();
            //printStackTrace()的意义在于在命令行打印异常信息在程序中出错的位置及原因

            System.out.println("Goodbye! Catch block.");

        } finally {
            // 下面定义了一个finally语句块
            System.out.println("I am finally block.");
        }
    }
}

TIM截图20181224142800.png

通过异常处理的学习以及捕获异常的手段,真正使程序在错综复杂的运行和使用环境中具有“金刚不败之身”。

试问,若在try语句块里有一个return语句,同时这个try语句块后面还有一个finally语句块,请问finally语句块里的代码会不会被执行?
public class TestC {

 @SuppressWarnings("static-access")
 public static void main(String[] args) {
     System.out.println("结果: " + new TestC().test());
 }

static int test(){
    int i = 1;
    try {
        System.out.println("try里面的i : " + i);
        return i;
    }finally{
        System.out.println("进入finally...");
        ++i;
         System.out.println("fianlly里面的i : " + i);
     }
 }

}
结果:
TIM截图20181224144325.png

在try语句中,在执行 return语句时,要返回的结果已经准备好了,就在此时,程序转到finally执行了。在转去之前,try中先把要返回的结果存放到不同于i的局部变量中去,执行完finally之后,返回结果。所以,使用finally中对变量i进行了改变,但是不会影响返回结果。

十、Java泛型
为啥需要泛型?
我们先来看一个例子:

List list = new ArrayList();
list.add("shiyanlou");
list.add("admin");
list.add(100);

for (int i = 0; i < list.size(); i++) {
     String name = (String) list.get(i); // 1
     System.out.println("name:" + name);
}

在上述代码中,定义了一个List类型的集合,先向其中加入了两个字符串类型的值,随后加入一个Integer类型的值。这是完全允许的,因为此时list默认的类型为Object类型。在之后的循环中,由于忘记了之前在list中也加入了Integer类型的值或其他编码原因,很容易出现类似于//1中的错误。因为编译阶段正常,而运行时会出现“java.lang.ClassCastException”异常。因此,导致此类错误编码过程中不易发现。
在如上的编码过程中,我们发现主要存在两个问题:

1.当我们将一个对象放入集合中,集合不会记住此对象的类型,当再次从集合中取出此对象时,改对象的编译类型变成了Object类型,但其运行时类型任然为其本身类型。
2.因此,//1处取出集合元素时需要人为的强制类型转化到具体的目标类型,且很容易出现“java.lang.ClassCastException”异常。
在 Java SE 5.0 以前操作集合有许多缺点,一是从集合取出对象时,需要执行类型转换操作,我们在前面讲过,集合中存储都是以 Object 对象进行存储的,这无疑让我们的操作变得麻烦。二是由于没有类型检查,可以向集合添加任意对象,不便于我们对集合的管理,有时候甚至会导致严重的错误。
而泛型就帮我们提供了类型参数,让我们提取规定好集合对象的类型。
//注意:引入了泛型以后,List<Object>, List<String>是两种不同的类型
ArrayList<String> files = new ArrayList<String>();
/*
*下面的代码是非法的
*List<Object> lo = files;
*/

我们在集合的类型后面添加上一对<>,尖括号中填上我们需要规范的集合里对象的类型,我们可以指定一个或多个类型参数的名字,同时也可以对类型参数的取值范围进行限定,多个类型参数之间用,分隔。这样编辑器便会在编译时帮我们检查出不符合规范的元素添加。
下面我们来看一看定义泛型的规则吧,同学们先有个印象,我们在后面定义泛型类和方法,以及使用泛型的时候,大家在结合我们这里讲解的规则,去深入地理解泛型吧!

1、泛型的类型参数只能是类类型(包括自定义类),不能是简单类型。
2、同一种泛型可以对应多个版本(因为参数类型是不确定的),不同版本的泛型类实例是不兼容的。
3、泛型的类型参数可以有多个。
4、泛型的参数类型可以使用 extends 语句,例如 。习惯上称为“有界类型”。
5、泛型的参数类型还可以是通配符类型。例如 Class<?> classType = Class.forName("java.lang.String");

定义泛型:

/*
使用T代表类型,无论何时都没有比这更具体的类型来区分它。如果有多个类型参数,我们可能使用字母表中T的临近的字母,比如S。
*/
class Test<T> {
    private T ob;

    /*
    定义泛型成员变量,定义完类型参数后,可以在定义位置之后的方法的任意地方使用类型参数,就像使用普通的类型一样。
    注意,父类定义的类型参数不能被子类继承。
    */

    //构造函数
    public Test(T ob) {
        this.ob = ob;
    }

    //getter 方法
    public T getOb() {
        return ob;
    }


    //setter 方法
    public void setOb(T ob) {
        this.ob = ob;
    }

    public void showType() {
        System.out.println("T的实际类型是: " + ob.getClass().getName());
    }
}

public class TestDemo {
    public static void main(String[] args) {
        // 定义泛型类 Test 的一个Integer版本
        Test<Integer> intOb = new Test<Integer>(88);
        intOb.showType();
        int i = intOb.getOb();
        System.out.println("value= " + i);
        System.out.println("----------------------------------");
        // 定义泛型类Test的一个String版本
        Test<String> strOb = new Test<String>("Hello Gen!");
        strOb.showType();
        String s = strOb.getOb();
        System.out.println("value= " + s);
    }
}

TIM截图2018122.png

使用泛型的方法:
①定义一个 Animal 类

public class Animal {
    public Animal(){
        System.out.println("我是动物");
    }
}

②定义一个 Dog 类

public class Dog extends Animal {
    public Dog(){
        System.out.println("我是狗");
    }
}

③定义一个 Test 类

public class Test {
/*
注意:定义带类型参数的方法,其主要目的是为了表达多个参数以及返回值之间的关系。例如本例子中T和S的继承关系, 返回值的类型和第一个类型参数的值相同。
*/
    public<T, S extends T> T testDemo(T t, S s){
        System.out.println("我是 T 类型,我的类型是" + t.getClass().getName());
        System.out.println("我是 S 类型,我的类型是" + s.getClass().getName());
        return t;
    }
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Test test = new Test();
        Dog d = new Dog();
        Animal a0 = new Animal();
        Animal a1  = test.testDemo(a0, d);
        System.out.println("我是整数 a,我的类型是" + a1.getClass().getName());
    }
}
上面的例子中我们对类型参数赋予了具体的类型,当然我们有时候也无法确定类型参数的类型,这个时候我们便可以使用通配符。如果仅仅是想实现多态,请优先使用通配符解决。
    示例代码:
    public void testDemo(List<?> s){
        for(Object obj:s){
            System.out.println("我的类型是" + obj.getClass().getName());
        }
    }

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Test test = new Test();
        Dog a0 = new Dog();
        Animal a1 = new Animal();
        List<Animal> s = new ArrayList<Animal>();
        s.add(a0);
        s.add(a1);
        test.testDemo(s);
    }
}

十一、Java枚举
认识枚举:
在有些情况下,变量的取值是限定在一个有限的集合内的。比如说,性别只有男和女,星期也只有星期一、星期二、星期三、…、星期天等。你可以将这些元素编号为1、2、3之类的,但这么做可能会让你的程序存在一些隐患,比如0通常还有false的含义。
枚举类型包含有限个命名的值。
从JDK 5.0开始,开发者可以自定义枚举类型,它的含义如下:
比如将星期声明为枚举类型的变量,你可以这样做:

enum Week { MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY };

这个声明定义的类型实际上是一个类,其中有7个实例。
和所有的类一样,你可以枚举类型中添加其构造器,以及一些域和方法。所以上面的声明你可以再补充一些内容:

public enum Week {
    MONDAY("MON"), TUESDAY("TUES"), WEDNESDAY("WED"), THURSDAY("THUR"),
    FRIDAY("FRI"), SATURDAY("SAT"), SUNDAY("SUN");
    //必须要先定义枚举类型,才能定义方法
    private String abbr;
    //声明的一个字符串,用于保存缩写信息
    private Week(String abbr) {
        this.abbr = abbr;
    }
    //声明的一个私有构造方法,该方法只能在构造枚举常量时被调用,可以使枚举元素具有指定的缩写信息
    public String getAbbr() {
        return abbr;
    }
    //通过该方法获得枚举元素的缩写
}

所有的枚举类型都继承了java.lang.Enum类,所以Enum类的一些方法也适用于这些枚举类型。例如:

equals(Object other),当指定对象等于此枚举常量时,返回 true。
toString(),返回枚举常量的名称,它包含在声明中。
valueOf(Class enumType, String name),返回带指定名称的指定枚举类型的枚举常量。

下面通过一个例子来学习枚举元素的基本特性,创建一个上述的Week类(代码在上方)和EnumPractice类。我们在代码的注释中继续来讲解它们的用法。
Week类你应该已经写好了,下面我们在EnumPractice类中添加一些代码:

public class EnumPractice {
    public static void main(String[] args) {
        for(Week week : Week.values()) {
            System.out.println("The order of " + week + " is " + week.ordinal());
            //使用ordinal()方法查看枚举元素的顺序
            System.out.println("Compare to MONDAY : " + week.compareTo(Week.MONDAY));
            //用compareTo()方法来将当前枚举元素与Week.MONDAY比较
            System.out.println("Equal to MONDAY ? " + week.equals(Week.MONDAY));
            //用equals()方法来将当前枚举元素与Week.MONDAY比较
            System.out.println("Equal to MONDAY by == ? " + ( week == Week.MONDAY ));
            //用比较运算符==来将当前枚举元素与Week.MONDAY比较
            //从这里你应该可以看到,可以直接使用==来比较两个枚举元素
            System.out.println("Name : " + week.name());
            //使用name()方法获得枚举元素的名称
            System.out.println("Abbreviation : " + week.getAbbr());
            //使用自定义的getAbbr()方法输出星期的缩写
            System.out.println("-------------------");
            //在每次循环快要结束时,打印一条分割线用于区分
        }
    }
}

这段程序中的for循环使用了下列条件格式:

for (循环变量类型 循环变量名称 : 要被遍历的对象) {
    循环体
}

“此类繁多,不能枚举。” ——清 李渔·《闲情偶寄》
综上创建EnumPractice类并将两段代码合写:

public class EnumPractice {
    public static void main(String[] args) {
        for(Week week : Week.values()) {
            System.out.println("The order of " + week + " is " + week.ordinal());
            //使用ordinal()方法查看枚举元素的顺序

            System.out.println("Compare to MONDAY : " + week.compareTo(Week.MONDAY));
            //用compareTo()方法来将当前枚举元素与Week.MONDAY比较

            System.out.println("Equal to MONDAY ? " + week.equals(Week.MONDAY));
            //用equals()方法来将当前枚举元素与Week.MONDAY比较

            System.out.println("Equal to MONDAY by == ? " + ( week == Week.MONDAY ));
            //用比较运算符==来将当前枚举元素与Week.MONDAY比较
            //从这里你应该可以看到,可以直接使用==来比较两个枚举元素

            System.out.println("Name : " + week.name());
            //使用name()方法获得枚举元素的名称

            System.out.println("Abbreviation : " + week.getAbbr());
            //使用自定义的getAbbr()方法输出星期的缩写

            System.out.println("-------------------");
            //在每次循环快要结束时,打印一条分割线用于区分
        }
    }
    public enum Week {

    MONDAY("MON"), TUESDAY("TUES"), WEDNESDAY("WED"), THURSDAY("THUR"),
    FRIDAY("FRI"), SATURDAY("SAT"), SUNDAY("SUN");
    //必须要先定义枚举类型,才能定义方法

    private String abbr;
    //声明的一个字符串,用于保存缩写信息

    private Week(String abbr) {
        this.abbr = abbr;
    }
    //声明的一个私有构造方法,该方法只能在构造枚举常量时被调用,可以使枚举元素具有指定的缩写信息

    public String getAbbr() {
        return abbr;
    }
    //通过该方法获得枚举元素的缩写
    }
}
shiyanlou:project/ $ java EnumPractice       [15:38:25]                                                             
The order of MONDAY is 0
Compare to MONDAY : 0
Equal to MONDAY ? true
Equal to MONDAY by == ? true
Name : MONDAY
Abbreviation : MON
-------------------
The order of TUESDAY is 1
Compare to MONDAY : 1
Equal to MONDAY ? false
Equal to MONDAY by == ? false
Name : TUESDAY
Abbreviation : TUES
-------------------
The order of WEDNESDAY is 2
Compare to MONDAY : 2
Equal to MONDAY ? false
Equal to MONDAY by == ? false
Name : WEDNESDAY
Abbreviation : WED
-------------------
The order of THURSDAY is 3
Compare to MONDAY : 3
Equal to MONDAY ? false
Equal to MONDAY by == ? false
Name : THURSDAY
Abbreviation : THUR
-------------------
The order of FRIDAY is 4
Compare to MONDAY : 4
Equal to MONDAY ? false
Equal to MONDAY by == ? false
Name : FRIDAY
Abbreviation : FRI
-------------------
The order of SATURDAY is 5
Compare to MONDAY : 5
Equal to MONDAY ? false
Equal to MONDAY by == ? false
Name : SATURDAY
Abbreviation : SAT
-------------------
The order of SUNDAY is 6
Compare to MONDAY : 6
Equal to MONDAY ? false
Equal to MONDAY by == ? false
Name : SUNDAY
Abbreviation : SUN
-------------------
Last modification:December 24th, 2018 at 03:25 pm
If you think my article is useful to you, please feel free to appreciate

Leave a Comment