Java面向对象编程(高级)三

在软件开发领域,面向对象编程(Object-Oriented Programming)是一种强大且广泛应用的编程范式,它将数据和操作封装在对象中,通过对象之间的交互来实现程序的逻辑。面向对象编程让我们能够以更加模块化、灵活和可维护的方式构建软件系统。

本文将链接上一篇文章,继续深入探讨面向对象编程的核心概念、优势以及如何在实际项目中应用这种编程范式

目录

9、枚举类

9.1 概述

9.2 定义枚举类(JDK5.0之前)

9.3 定义枚举类(JDK5.0之后)

9.3.1 enum关键字声明枚举

9.3.2 enum方式定义的要求和特点 

9.4 enum中常用方法 

9.5 实现接口的枚举类 

10、注解(Annotation)

10.1 注解概述

10.1.1 什么是注解

10.1.2 注解与注释

10.1.3 注解的重要性

10.2 常见的Annotation作用

10.2.1 生成文档响应的注解

10.2.2 在编译时进行格式检查(JDK内置的三个基本注解)

10.3 三个最基本的注解

10.3.1 @Override

10.3.2 @Deprecated

10.3.3 @SuppressWarnings

10.4 自定义注解的使用

10.4.1 声明自定义注解

10.4.2 使用自定义注解

10.4.3 读取和处理自定义注解

11、包装类

11.1 有哪些包装类

11.3 自定义包装类

11.4 包装类与基本数据类型间的转换

11.4.1 装箱

11.4.2 拆箱

11.5 基本数据类型、包装类与字符串间的转换 

11.5.1 基本数据类型转为字符串

11.5.2 字符串转换为基本数据类型

11.6 包装类的其他API

11.6.1 数据类型的最大最小值

11.6.2 字符转大小写

11.6.3 整数转进制 

11.6.4 比较的方法

11.7 包装类对象的特点

11.7.1 包装类缓存对象

11.7.2 类型转换问题

11.7.3 包装类对象不可变


 

9、枚举类

9.1 概述

  • 枚举类型本质上也是一种类,只不过是这个类的对象是有限的、固定的几个,不能让用户随意创建。

  • 枚举类的例子举不胜举:

    • 星期:Monday(星期一)......Sunday(星期天)

    • 性别:Man(男)、Woman(女)

    • 月份:January(1月)......December(12月)

    • 季节:Spring(春节)......Winter(冬天)

    • 三原色:red(红色)、green(绿色)、blue(蓝色)

    • 支付方式:Cash(现金)、WeChatPay(微信)、Alipay(支付宝)、BankCard(银行卡)、CreditCard(信用卡)

    • 就职状态:Busy(忙碌)、Free(空闲)、Vocation(休假)、Dimission(离职)

    • 订单状态:Nonpayment(未付款)、Paid(已付款)、Fulfilled(已配货)、Delivered(已发货)、Checked(已确认收货)、Return(退货)、Exchange(换货)、Cancel(取消)

    • 线程状态:创建、就绪、运行、阻塞、死亡

  • 若枚举只有一个对象, 则可以作为一种单例模式的实现方式。

  • 枚举类的实现:

    • 在JDK5.0 之前,需要程序员自定义枚举类型。

    • 在JDK5.0 之后,Java支持enum关键字来快速定义枚举类型。

9.2 定义枚举类(JDK5.0之前)

在JDK5.0 之前如何声明枚举类呢?

  • 私有化类的构造器,保证不能在类的外部创建其对象

  • 在类的内部创建枚举类的实例。声明为:public static final ,对外暴露这些常量对象

  • 对象如果有实例变量,应该声明为private final(建议,不是必须),并在构造器中初始化

示例代码:

class Season{
    private final String SEASONNAME;//季节的名称
    private final String SEASONDESC;//季节的描述
    private Season(String seasonName,String seasonDesc){
        this.SEASONNAME = seasonName;
        this.SEASONDESC = seasonDesc;
    }
    public static final Season SPRING = new Season("春天", "春暖花开");
    public static final Season SUMMER = new Season("夏天", "夏日炎炎");
    public static final Season AUTUMN = new Season("秋天", "秋高气爽");
    public static final Season WINTER = new Season("冬天", "白雪皑皑");

    @Override
    public String toString() {
        return "Season{" +
                "SEASONNAME='" + SEASONNAME + '\'' +
                ", SEASONDESC='" + SEASONDESC + '\'' +
                '}';
    }
}
class SeasonTest{
    public static void main(String[] args) {
        System.out.println(Season.AUTUMN);
    }
}

9.3 定义枚举类(JDK5.0之后)

9.3.1 enum关键字声明枚举

[修饰符] enum 枚举类名{
    常量对象列表
}

[修饰符] enum 枚举类名{
    常量对象列表;
    
    对象的实例变量列表;
}

示例:

public enum Week {
    MONDAY,TUESDAY,WEDNESDAY,THURSDAY,FRIDAY,SATURDAY,SUNDAY;
}
public class TestEnum {
	public static void main(String[] args) {
		Season spring = Season.SPRING;
		System.out.println(spring);
	}
}

9.3.2 enum方式定义的要求和特点 

  • 枚举类的常量对象列表必须在枚举类的首行,因为是常量,所以建议大写。

  • 列出的实例系统会自动添加 public static final 修饰。

  • 如果常量对象列表后面没有其他代码,那么“;”可以省略,否则不可以省略“;”。

  • 编译器给枚举类默认提供的是private的无参构造,如果枚举类需要的是无参构造,就不需要声明,写常量对象列表时也不用加参数

  • 如果枚举类需要的是有参构造,需要手动定义,有参构造的private可以省略,调用有参构造的方法就是在常量对象名后面加(实参列表)就可以。

  • 枚举类默认继承的是java.lang.Enum类,因此不能再继承其他的类型。

  • JDK5.0 之后switch,提供支持枚举类型,case后面可以写枚举常量名,无需添加枚举类作为限定。

示例:

public enum SeasonEnum {
    SPRING("春天","春风又绿江南岸"),
    SUMMER("夏天","映日荷花别样红"),
    AUTUMN("秋天","秋水共长天一色"),
    WINTER("冬天","窗含西岭千秋雪");

    private final String seasonName;
    private final String seasonDesc;
    
    private SeasonEnum(String seasonName, String seasonDesc) {
        this.seasonName = seasonName;
        this.seasonDesc = seasonDesc;
    }
    public String getSeasonName() {
        return seasonName;
    }
    public String getSeasonDesc() {
        return seasonDesc;
    }
}

9.4 enum中常用方法 

1、String toString(): 默认返回的是常量名(对象名),可以继续手动重写该方法!
2、static 枚举类型[] values():返回枚举类型的对象数组。该方法可以很方便地遍历所有的枚举值,是一个静态方法
3、static 枚举类型 valueOf(String name):可以把一个字符串转为对应的枚举类对象。要求字符串必须是枚举类对象的“名字”。如不是,会有运行时异常:IllegalArgumentException。 
4、String name():得到当前枚举常量的名称。建议优先使用toString()。
5、int ordinal():返回当前枚举常量的次序号,默认从0开始

示例:
 

import java.util.Scanner;

public class TestEnumMethod {
    public static void main(String[] args) {
        //values()
        Week[] values = Week.values();
        for (int i = 0; i < values.length; i++) {
            //ordinal()、name()
            System.out.println((values[i].ordinal()+1) + "->" + values[i].name());
        }
        System.out.println("------------------------");

        Scanner input = new Scanner(System.in);
        System.out.print("请输入星期值:");
        int weekValue = input.nextInt();
        Week week = values[weekValue-1];
        //toString()
        System.out.println(week);

        System.out.print("请输入星期名:");
        String weekName = input.next();
        //valueOf()
        week = Week.valueOf(weekName);
        System.out.println(week);

        input.close();
    }
}

9.5 实现接口的枚举类 

  • 和普通 Java 类一样,枚举类可以实现一个或多个接口

  • 若每个枚举值在调用实现的接口方法呈现相同的行为方式,则只要统一实现该方法即可。

  • 若需要每个枚举值在调用实现的接口方法呈现出不同的行为方式,则可以让每个枚举值分别来实现该方法

语法格式:

//1、枚举类可以像普通的类一样,实现接口,并且可以多个,但要求必须实现里面所有的抽象方法!
enum A implements 接口1,接口2{
	//抽象方法的实现
}

//2、如果枚举类的常量可以继续重写抽象方法!
enum A implements 接口1,接口2{
    常量名1(参数){
        //抽象方法的实现或重写
    },
    常量名2(参数){
        //抽象方法的实现或重写
    },
    //...
}

示例:

interface Info{
	void show();
}

//使用enum关键字定义枚举类
enum Season1 implements Info{
	//1. 创建枚举类中的对象,声明在enum枚举类的首位
	SPRING("春天","春暖花开"){
		public void show(){
			System.out.println("春天在哪里?");
		}
	},
	SUMMER("夏天","夏日炎炎"){
		public void show(){
			System.out.println("宁静的夏天");
		}
	},
	AUTUMN("秋天","秋高气爽"){
		public void show(){
			System.out.println("秋天是用来分手的季节");
		}
	},
	WINTER("冬天","白雪皑皑"){
		public void show(){
			System.out.println("2002年的第一场雪");
		}
	};
	
	//2. 声明每个对象拥有的属性:private final修饰
	private final String SEASON_NAME;
	private final String SEASON_DESC;
	
	//3. 私有化类的构造器
	private Season1(String seasonName,String seasonDesc){
		this.SEASON_NAME = seasonName;
		this.SEASON_DESC = seasonDesc;
	}
	
	public String getSEASON_NAME() {
		return SEASON_NAME;
	}

	public String getSEASON_DESC() {
		return SEASON_DESC;
	}
}

10、注解(Annotation)

10.1 注解概述

10.1.1 什么是注解

注解(Annotation)是从JDK5.0开始引入,以“@注解名”在代码中存在。例如:

@Override

@Deprecated

@SuppressWarnings(value=”unchecked”)

Annotation 可以像修饰符一样被使用,可用于修饰包、类、构造器、方法、成员变量、参数、局部变量的声明。还可以添加一些参数值,这些信息被保存在 Annotation 的 “name=value” 对中。

注解可以在类编译、运行时进行加载,体现不同的功能。

10.1.2 注解与注释

注解也可以看做是一种注释,通过使用 Annotation,程序员可以在不改变原有逻辑的情况下,在源文件中嵌入一些补充信息。但是,注解,不同于单行注释和多行注释。

  • 对于单行注释和多行注释是给程序员看的。

  • 而注解是可以被编译器或其他程序读取的。程序还可以根据注解的不同,做出相应的处理。

10.1.3 注解的重要性

在JavaSE中,注解的使用目的比较简单,例如标记过时的功能,忽略警告等。在JavaEE/Android中注解占据了更重要的角色,例如用来配置应用程序的任何切面,代替JavaEE旧版中所遗留的繁冗代码XML配置等。

未来的开发模式都是基于注解的,JPA是基于注解的,Spring2.5以上都是基于注解的,Hibernate3.x以后也是基于注解的,Struts2有一部分也是基于注解的了。注解是一种趋势,一定程度上可以说:框架 = 注解 + 反射 + 设计模式

10.2 常见的Annotation作用

10.2.1 生成文档响应的注解

@author 标明开发该类模块的作者,多个作者之间使用,分割
@version 标明该类模块的版本
@see 参考转向,也就是相关主题
@since 从哪个版本开始增加的
@param 对方法中某参数的说明,如果没有参数就不能写
@return 对方法返回值的说明,如果方法的返回值类型是void就不能写
@exception 对方法可能抛出的异常进行说明 ,如果方法没有用throws显式抛出的异常就不能写

10.2.2 在编译时进行格式检查(JDK内置的三个基本注解)

@Override: 限定重写父类方法,该注解只能用于方法

@Deprecated: 用于表示所修饰的元素(类,方法等)已过时。通常是因为所修饰的结构危险或存在更好的选择

@SuppressWarnings: 抑制编译器警告

public class AnnotationTest{
 
	public static void main(String[] args) {
		@SuppressWarnings("unused")
		int a = 10;
	}
	@Deprecated
	public void print(){
		System.out.println("过时的方法");
	}
 
	@Override
	public String toString() {
		return "重写的toString方法()";
	}
}

10.3 三个最基本的注解

10.3.1 @Override

  • 用于检测被标记的方法为有效的重写方法,如果不是,则报编译错误!

  • 只能标记在方法上。

  • 它会被编译器程序读取。

10.3.2 @Deprecated

  • 用于表示被标记的数据已经过时,不推荐使用。

  • 可以用于修饰 属性、方法、构造、类、包、局部变量、参数。

  • 它会被编译器程序读取。

10.3.3 @SuppressWarnings

  • 抑制编译警告。当我们不希望看到警告信息的时候,可以使用 SuppressWarnings 注解来抑制警告信息

  • 可以用于修饰类、属性、方法、构造、局部变量、参数

  • 它会被编译器程序读取。

  • 可以指定的警告类型有(了解)

    • all,抑制所有警告

    • unchecked,抑制与未检查的作业相关的警告

    • unused,抑制与未用的程式码及停用的程式码相关的警告

    • deprecation,抑制与淘汰的相关警告

    • nls,抑制与非 nls 字串文字相关的警告

    • null,抑制与空值分析相关的警告

    • rawtypes,抑制与使用 raw 类型相关的警告

    • static-access,抑制与静态存取不正确相关的警告

    • static-method,抑制与可能宣告为 static 的方法相关的警告

    • super,抑制与置换方法相关但不含 super 呼叫的警告

示例:

import java.util.ArrayList;

public class TestAnnotation {
    @SuppressWarnings("all")
    public static void main(String[] args) {
        int i;

        ArrayList list = new ArrayList();
        list.add("hello");
        list.add(123);
        list.add("world");

        Father f = new Son();
        f.show();
        f.methodOl();
    }
}

class Father{
    @Deprecated
    void show() {
        System.out.println("Father.show");
    }
    void methodOl() {
        System.out.println("Father Method");
    }
}

class Son extends Father{
/*	@Override
	void method01() {
		System.out.println("Son Method");
	}*/
}

10.4 自定义注解的使用

一个完整的注解应该包含三个部分: (1)声明 (2)使用 (3)读取

10.4.1 声明自定义注解

[元注解]
[修饰符] @interface 注解名{
    [成员列表]
}
  • 自定义注解可以通过四个元注解@Retention,@Target,@Inherited,@Documented,分别说明它的声明周期,使用位置,是否被继承,是否被生成到API文档中。

  • Annotation 的成员在 Annotation 定义中以无参数有返回值的抽象方法的形式来声明,我们又称为配置参数。返回值类型只能是八种基本数据类型、String类型、Class类型、enum类型、Annotation类型、以上所有类型的数组

  • 可以使用 default 关键字为抽象方法指定默认返回值

  • 如果定义的注解含有抽象方法,那么使用时必须指定返回值,除非它有默认值。格式是“方法名 = 返回值”,如果只有一个抽象方法需要赋值,且方法名为value,可以省略“value=”,所以如果注解只有一个抽象方法成员,建议使用方法名value。

import java.lang.annotation.*;

@Inherited
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Table {
    String value();
}
import java.lang.annotation.*;

@Inherited
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Column {
    String columnName();
    String columnType();
}

10.4.2 使用自定义注解

@Table("t_stu")
public class Student {
    @Column(columnName = "sid",columnType = "int")
    private int id;
    @Column(columnName = "sname",columnType = "varchar(20)")
    private String name;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "Student{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }
}

10.4.3 读取和处理自定义注解

自定义注解必须配上注解的信息处理流程才有意义。

我们自己定义的注解,只能使用反射的代码读取。所以自定义注解的声明周期必须是RetentionPolicy.RUNTIME。


11、包装类

11.1 有哪些包装类

Java针对八种基本数据类型定义了相应的引用类型:包装类(封装类)。有了类的特点,就可以调用类中的方法,Java才是真正的面向对象。

11.3 自定义包装类

public class MyInteger {
    int value;

    public MyInteger() {
    }

    public MyInteger(int value) {
        this.value = value;
    }

    @Override
    public String toString() {
        return String.valueOf(value);
    }
}

11.4 包装类与基本数据类型间的转换

11.4.1 装箱

装箱:把基本数据类型转为包装类对象

转为包装类的对象,是为了使用专门为对象设计的API和特性

基本数值---->包装对象

Integer obj1 = new Integer(4);//使用构造函数函数
Float f = new Float(“4.56”);
Long l = new Long(“asdf”);  //NumberFormatException

Integer obj2 = Integer.valueOf(4);//使用包装类中的valueOf方法

11.4.2 拆箱

拆箱:把包装类对象拆为基本数据类型

转为基本数据类型,一般是因为需要运算,Java中的大多数运算符是为基本数据类型设计的。比较、算术等

包装对象---->基本数值

Integer obj = new Integer(4);
int num1 = obj.intValue();

自动装箱与拆箱:

由于我们经常要做基本类型与包装类之间的转换,从JDK5.0开始,基本类型与包装类的装箱、拆箱动作可以自动完成。例如:

Integer i = 4;//自动装箱。相当于Integer i = Integer.valueOf(4);
i = i + 5;//等号右边:将i对象转成基本数值(自动拆箱)
i.intValue() + 5;
//加法运算完成后,再次装箱,把基本数值转成对象。

注意:只能与自己对应的类型之间才能实现自动装箱与拆箱。

11.5 基本数据类型、包装类与字符串间的转换 

11.5.1 基本数据类型转为字符串

1、调用字符串重载的valueOf()方法

int a = 10;
//String str = a;//错误的

String str = String.valueOf(a);

2、更直接的方式

int a = 10;

String str = a + "";

11.5.2 字符串转换为基本数据类型

1、除了Character类之外,其他所有包装类都具有parseXxx静态方法可以将字符串参数转换为对应的基本类型。

  • 2、public static int parseInt(String s):将字符串参数转换为对应的int基本类型。

  • public static long parseLong(String s):将字符串参数转换为对应的long基本类型。

  • public static double parseDouble(String s):将字符串参数转换为对应的double基本类型。

2、 字符串转为包装类,然后可以自动拆箱为基本数据类型

  • public static Integer valueOf(String s):将字符串参数转换为对应的Integer包装类,然后可以自动拆箱为int基本类型

  • public static Long valueOf(String s):将字符串参数转换为对应的Long包装类,然后可以自动拆箱为long基本类型

  • public static Double valueOf(String s):将字符串参数转换为对应的Double包装类,然后可以自动拆箱为double基本类型

3、通过包装类的构造器实现

int a = Integer.parseInt("整数的字符串");
double d = Double.parseDouble("小数的字符串");
boolean b = Boolean.parseBoolean("true或false");

int a = Integer.valueOf("整数的字符串");
double d = Double.valueOf("小数的字符串");
boolean b = Boolean.valueOf("true或false");

int i = new Integer(“12”);

11.6 包装类的其他API

11.6.1 数据类型的最大最小值

Integer.MAX_VALUE和Integer.MIN_VALUE
    
Long.MAX_VALUE和Long.MIN_VALUE
    
Double.MAX_VALUE和Double.MIN_VALUE

11.6.2 字符转大小写

Character.toUpperCase('x');

Character.toLowerCase('X');

11.6.3 整数转进制 

Integer.toBinaryString(int i) 
    
Integer.toHexString(int i)
    
Integer.toOctalString(int i)

11.6.4 比较的方法

Double.compare(double d1, double d2)
    
Integer.compare(int x, int y) 

11.7 包装类对象的特点

11.7.1 包装类缓存对象

包装类缓存对象
byte-128~127
short-128~127
integer-128~127
long-128~127
float没有
double没有
character0~127
booleantrue和false
Integer a = 1;
Integer b = 1;
System.out.println(a == b);//true

Integer i = 128;
Integer j = 128;
System.out.println(i == j);//false

Integer m = new Integer(1);//新new的在堆中
Integer n = 1;//这个用的是缓冲的常量对象,在方法区
System.out.println(m == n);//false

Integer x = new Integer(1);//新new的在堆中
Integer y = new Integer(1);//另一个新new的在堆中
System.out.println(x == y);//false
Double d1 = 1.0;
Double d2 = 1.0;
System.out.println(d1==d2);//false 比较地址,没有缓存对象,每一个都是新new的

11.7.2 类型转换问题

Integer i = 1000;
double j = 1000;
System.out.println(i==j);//true  会先将i自动拆箱为int,然后根据基本数据类型“自动类型转换”规则,转为double比较
Integer i = 1000;
int j = 1000;
System.out.println(i==j);//true 会自动拆箱,按照基本数据类型进行比较
Integer i = 1;
Double d = 1.0
System.out.println(i==d);//编译报错

11.7.3 包装类对象不可变

public class TestExam {
	public static void main(String[] args) {
		int i = 1;
		Integer j = new Integer(2);
		Circle c = new Circle();
		change(i,j,c);
		System.out.println("i = " + i);//1
		System.out.println("j = " + j);//2
		System.out.println("c.radius = " + c.radius);//10.0
	}
	
	/*
	 * 方法的参数传递机制:
	 * (1)基本数据类型:形参的修改完全不影响实参
	 * (2)引用数据类型:通过形参修改对象的属性值,会影响实参的属性值
	 * 这类Integer等包装类对象是“不可变”对象,即一旦修改,就是新对象,和实参就无关了
	 */
	public static void change(int a ,Integer b,Circle c ){
		a += 10;
//		b += 10;//等价于  b = new Integer(b+10);
		c.radius += 10;
		/*c = new Circle();
		c.radius+=10;*/
	}
}
class Circle{
	double radius;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值