学习了一定基础后,开始更加深入的学习面向对象,包含static,final两个关键字,面向对象编程三大特征之继承和多态。以及对于抽象类,内部类,接口,枚举,泛型的学习。
目录
4.final
1.static
静态,修饰成员变量,成员方法。
(1)修饰成员变量
成员变量按照有无static修饰,分为两种:
- 类变量:有static修饰,属于类,在计算机里只有一份,会被类的全部对象共享
- 实例变量(对象的变量):无static修饰,属于每个对象
package W.KN.d1_static;
public class Student {
//类变量
static String name;
//实例变量
int age;
}
package W.KN.d1_static;
public class Text {
public static void main(String[] args) {
//目标:掌握有无static修饰成员变量的用法,特点
//1.类变量的用法
//类名.类变量(推荐)
Student.name = "郑大风";
//对象.类变量(不推荐)
Student s1 = new Student();
s1.name = "陈清流";
Student s2 = new Student();
System.out.println(s1.name);
System.out.println(Student.name);
//实例变量的用法:属于每个对象
s1.age = 45;
s2.age = 123;
System.out.println(s1.age);
System.out.println(s2.age);
}
}
成员变量执行原理:
类变量,与类一起加载一次,在堆内存中开辟一份空间(且只有一份),后续不论通过类或者对象访问修改的都是同一块空间。实例变量随对象的创建而创建,访问时还是通过对象的地址
(2) 修饰成员变量的应用场景
在开发中,如果某个数据只需要一份,且希望能够被共享(访问,修改),则该数据可以被定义为类变量使用。
案例
系统启动后,要求用户类可以记住自己创建了多少个用户对象
package W.KN.d1_static;
public class User {
//类变量:对外公开
public static int number;
public User(){
//User.number++;
//注意:在同一类中,访问自己类的类变量,可以省略类名不写
number++;
}
}
package W.KN.d1_static;
public class Text2 {
public static void main(String[] args) {
//目标:案例理解类变量的应用场景
User u1 = new User();
User u2 = new User();
User u3 = new User();
User u4 = new User();
System.out.println(User.number);
}
}
(3)修饰成员方法
成员方法按照有无static修饰,分为两种:
- 类方法:有static修饰,属于类(类和对象都可以访问)
- 实例方法:无static修饰,属于对象(只有对象可以访问)
package W.KN.d1_static;
public class Student {
public static void print(){
System.out.println("HelloWorld");
}
//实例方法
public void printfPass(double score){
System.out.println("成绩"+(score >= 60 ? "及格":"不及格"));
}
}
package W.KN.d1_static;
public class Text3 {
public static void main(String[] args) {
//目标:掌握有无static修饰方法的用法
//类方法的用法
//类名调用
Student.print();
Student s = new Student();
s.print();
s.printfPass(100);
}
}
成员方法执行原理:
对象之所以可以调用类方法,是由于每个对象都会在堆内存中存储一份类的地址,可以通过地址去调用这些方法,至于类为什么不能调用成员方法,很简单,一是类中没有这些方法的地址,他们都在对象的空间中,二是一般这些方法都有涉及参数,类是无法访问的。
补充: main方法
(4)修饰成员方法的应用场景
类方法最常用的应用场景是做工具类(完成一些功能,给开发人员共同使用)
优点是调用方便,提高效率。工具类没有创建对象的需求,建议将工具类的构造器私有
案例:
对于实现验证码功能出现了重复,为避免浪费空间,在工具类中定义一个类方法实现
package W.KN.d1_static;
import java.util.Random;
public class MyUtil {
public static String creatCoe(int n){
//2.定义两个变量,一个用来存储最终产生的随机验证码 一个用来记住可能用到的全部字符
String code = "";
String data = "abccdefghigklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
Random r = new Random();
//3.定义一个循环 产生每位随机字符
for (int i = 0; i < n; i++) {
int index = r.nextInt(data.length());
code += data.charAt(index);
}
return code;
}
}
(5)注意事项
- 类方法中可以直接访问类的成员,不可以直接访问实例对象
- 实例方法中既可以直接访问类成员,也可以直接访问实例成员
- 实例方法中可以出现this关键字,类方法中不可以出现this关键字
(6)应用知识
代码块
代码块是类的5大成分之一(成员变量,构造器,方法,代码块,内部块)
分类
静态代码块——格式:static{ }
特点:类加载时自动执行,类只加载一次,所以静态代码只执行一次
作用:完成类的初始化,比如对类的初始化赋值(成员复杂操作赋值)
实例代码块——格式:{ }
特点:每次创建对象时,执行实例代码块,并在构造器前执行
作用:同构造器,是用来完成对象的初始化的(实例变量进行初始化赋值)
package d3_tatic;
public class Student {
static int number = 80;
static String name;
//静态代码块
static {
System.out.println("静态代码块执行了...");
name = "楠楠";
}
//实例代码块
//用来执行一些构造器中的重复语句
{
System.out.println("实例代码块执行了。。。");
}
public Student(){
System.out.println("无参数构造器执行了。。。");
}
public Student(String name){
System.out.println("有参数构造器执行了。。。");
}
}
package d3_tatic;
public class Text {
public static void main(String[] args) {
//目标:认识两种代码块,了解他们的特点和基本作用
System.out.println(Student.number);
System.out.println(Student.number);
System.out.println(Student.name);
Student s1 =new Student();
Student s2 =new Student("楠楠");
}
}
单例设计模式
设计模式(Design pattern)
一种问题有n种解法,最优的解法被人总结出来,称之为设计模式
单例设计模式: 确保一个类只有一个对象 避免浪费内存
写法:
- 把类的构造器私有
- 定义一个类变量记住类的一个对象
- 定义一个类方法,返回对象
应用场景:
参照 Runtime 的写法 (返回当前编译环境)
实现方式:
- 饿汉式单例:拿对象时,对象早就创建好了
- 懒汉式单例:拿对象时,才开始创建对象
- .......
2.继承
(1)介绍与入门
java提供了一个关键字extends,使用可以让一个类和另一个类建立起父子关系。
继承的特点:子类能继承父类的非私有成员(成员变量,成员方法)
继承后的创建:子类的对象是由子类和父类共同完成的
package d5_extends;
//父类
public class A {
public int i;
public void print1(){
System.out.println("==print1==");
}
private int j;
private void print2(){
System.out.println("==print2");
}
}
package d5_extends;
//子类
public class B extends A{
public void printf3(){
System.out.println("==print3==");
System.out.println(i);//子类可以世界使用父类公开的成员
print1();
//print2(); 父类私有的不可继承
}
}
package d5_extends;
public class Text {
public static void main(String[] args) {
//目标:认识继承,掌握继承的特点
B b = new B();
System.out.println(b.i);
b.print1();
b.printf3();
}
}
继承的执行原理:
子类在方法区中读取时,会将自己的父类也读取一次。对于这个对象就是按照两个模式去创建的
继承的好处:
减少重复代码的编写
package d6_extends; public class People { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } } package d6_extends; public class Teacher extends People{ private String skill; public String getSkill() { return skill; } public void setSkill(String skill) { this.skill = skill; } } package d6_extends; public class Text { public static void main(String[] args) { //目标:清楚继承的好处 Teacher t = new Teacher(); t.setName("楠楠"); t.setSkill("java"); System.out.println(t); } }
(2)注意事项
[1] 权限修饰符
权限修饰符就是用来限制类中的成员(成员变量,成员方法,构造器,代码块...)能够访问的范围。
修饰符 | 在本类中 | 同一个包下的其他类里 | 任意包下的子类里 | 任意包的任意类里 |
private | √ | |||
省缺 | √ | √ | ||
protected | √ | √ | √ | |
public | √ | √ | √ | √ |
private < 省缺 < protected < public
package d9_modifer;
public class Fu {
private void privateMethod(){
System.out.println("private");
}
void Method(){
System.out.println("省缺");
}
protected void protectedMethod(){
System.out.println("protected");
}
public void publicMethod(){
System.out.println("public");
}
public void text(){
privateMethod();
Method();
protectedMethod();
publicMethod();
}
}
[2] 单继承,Object类
java是单继承的,类不支持多继承,但是支持多层继承,java中所有类都是继承于Object类。
[3] 方法重写
当子类觉得父类中某个方法不好用,或者无法满足自己的需求时,子类可以重写一个方法名称,参数列表一致的方法去覆盖父类的方法。重写后,java遵循就近原则访问方法。 (重写后,还想访问父类的方法或者变量,使用super.方法指定访问)
package d7_feature;
public class A {
public void print(){
System.out.println("111");
}
public void printf(int a,int b){
System.out.println("11122112");
}
}
package d7_feature;
public class B extends A {
//方法重写
public void print(){
System.out.println("222");
}
public void printf(int a,int b){
System.out.println("22221313");
}
}
package d7_feature;
public class Text {
public static void main(String[] args) {
B b = new B();
b.print();
b.printf(1,2);
}
}
注意事项:
- 重写小技巧:使用Override注解,他可以指定java编译器,检查我们方法重写的格式是否正确,代码可读性会更好。(@Overrride)
- 子类重写父类方法时,访问权限必须大于或者等于父类该方法的权限(public>protected>省缺)
- 重写的方法返回值类型,必须于被重写的方法返回类型一致,或者范围更小。
- 私有方法,静态方法不能被重写,如果重写会报错。
[4]子类访问其他成员的特点
子类方法中访问其他成员(成员变量,成员方法),是依照就近原则的。
[5] 子类构造器的特点
子类的全部构造器,都会先调用父类的构造器,再执行自己
package d10_constructor;
class F{
public F(){
System.out.println("父类F的 无参数构造器 执行了");
}
}
class Z extends F{
public Z(){
super();//默认存在的
System.out.println("子类Z的 无参数构造器 执行了");
}
public Z(String name){
System.out.println("子类Z的 有参数构造器 执行了");
}
}
public class Text {
public static void main(String[] args) {
//目标:先认识子类构造器的特点,再掌握这个特点的常见应用场景
Z z = new Z();
Z z1 = new Z("楠楠");
}
}
this(...)调用兄弟构造器(this() 和super()必须在构造器第一行)
package d10_constructor;
class Student{
private String name;
private int age;
private String school;
public Student(String name,int age){
this(name,age,"中北大学");
}
public Student() {
}
public Student(String name, int age, String school) {
this.name = name;
this.age = age;
this.school = school;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getSchool() {
return school;
}
public void setSchool(String school) {
this.school = school;
}
}
public class Text {
public static void main(String[] args) {
//目标:先认识子类构造器的特点,再掌握这个特点的常见应用场景
//学习this调用该类的其他构造器
Student s2 = new Student("楠楠",19);
System.out.println(s2.getName());
System.out.println(s2.getAge());
System.out.println(s2.getSchool());
}
}
3.多态
(1)认识与入门
多态是在继承/实现情况下的一种现象,表现为:对象多态,行为多态。
前提:有继承/实现关系,存在父类引用子类对象,存在方法重写(才会有行为多态)
(2)使用好处
- 在多态形式下,右边对象是解耦合的,更便于拓展和维护。
- 定义方法时,使用父类类型的形参,可以接收一切子类对象,扩展性强,更便利
*多态下会产生下一个问题 :多态下不能使用子类的独有功能。
package d2_OPP;
public class Student extends People{
@Override
public void run(){
System.out.println("学生跑的很快");
}
public void text(){
System.out.println("学生需要考试");
}
}
package d2_OPP;
public class Teacher extends People {
@Override
public void run(){
System.out.println("老师跑的气喘嘘嘘");
}
public void teach(){
System.out.println("老师需要教书");
}
}
package d2_OPP;
public class Text {
public static void main(String[] args) {
//理解多态的好处
//好处1 可以实现解耦合 右边对象随时切换 后续业务随之改变
People p1 = new Student(); //new Student
p1.run();
//p1.text();
Student s = new Student();
go(s);
Teacher t = new Teacher();
go(t);
}
//好处2 可以使用父类类型的变量作为形参,可以接收一切子类对象
public static void go(People p){
}
}
(3)多态下的类型转换问题
类型转换:(解决多态下不能调用子类独有方法的问题)
- 自动类型转换:父类 变量名 = new 子类();
- 强制类型转换:子类 变量名 = (子类)父类变量
强制类型看转换的一个注意事项:
- 存在继承/实现关系就可以在编译阶段进行强制类型转化,编译不报错
- 运行时,如果发现对象的真实类型与强转后的类型不同,会报类型转换异常(ClassCastException)的错误出来
- (使用关键字 instanceof 进行判断真实类型)
package d2_OPP;
public class Text {
public static void main(String[] args) {
//理解多态的好处
//好处1 可以实现解耦合 右边对象随时切换 后续业务随之改变
People p1 = new Student(); //new Student
p1.run();
//强制类型转化
if(p1 instanceof Student) {
Student s1 = (Student) p1;
s1.text();
}
else {
Teacher t2 = new Teacher();
t2.teach();
}
//就可以执行独特功能
Student s = new Student();
go(s);
Teacher t = new Teacher();
go(t);
}
//好处2 可以使用父类类型的变量作为形参,可以接收一切子类对象
public static void go(People p){
if(p instanceof Student) {
Student s1 = (Student) p;
s1.run();
}
else {
Teacher t2 = (Teacher) p;
t2.run();
}
}
}
4.final
(1)认识与了解
final关键字是最终的意思,可以修饰类,方法,变量
- 修饰类 :最终类 特点是不能被继承了
- 修饰方法:最终方法 特点是不能被重写了
- 修饰变量:该变量只能被赋值一次
- (final修饰基本类型的变量,变量存储的数据不能改变)
- (final修饰引用类型的变量 地址不能改变 但是地址指向的内容是可以改变的)
package d3_final;
public class Text {
public static void main(String[] args) {
//final 修饰变懒 有且仅能赋值一次
/*
变量
一。局部变量
二。成员变量
1.静态成员变量
2.实例成员变量
*/
final int a;
a = 5;
// a = 6; //第二次赋值会出错 保护数值
}
}
//1.final 修饰类,类不能被继承 (一般用于工作类)
final class A{}
//class B extends A{}
//2.final 修饰方法 方法不能被重写
class C{
public final void text (){}
}
/*class D extends C{
@Override
public void text(){}
}*/
(2)常量详解
- 使用了static final修饰的成员变量就称为常量
- 作用:通常用于记录系统的配置信息
注意:命名规范:大写英文字母,多个单词使用下划线
常量的优势和执行原理:
- 代码可读性好,可维护性也更好
- 编译后,常量会进行 “宏替换”
5.抽象类
(1)认识与入门
java 有一个关键字 abstract 抽象 用来修饰类和方法
package d4_abstrsact;
//抽象类
public abstract class A {
//抽象方法 必须用abstract修饰,只有方法签名 一定不能有方法体
public abstract void run();
}
抽象类的注意事项特点:
- 抽象类不一定有抽象方法,有抽象方法的类一定是抽象类。
- 类该有的成员成员变量,方法,构造器,抽象类都可以有。
- 抽象类最主要的特点,抽象类不能创建对象,仅作为一特殊的父类让子类继承并实现。
- 一个类继承抽象类必须重写抽象类的全部抽象方法。否则这个类也必须定义为抽象类。
(2)使用好处
父类知道每个子类都要做某个行为,但每个子类要做的情况不一样,父类就定义为抽象方法。交给子类去重写实现。我们设计这样的抽象类就是为了更好的支持多态。
package d4_abstrsact;
public abstract class Animal {
private String name;
public abstract void cry();
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
package d4_abstrsact;
public class Dog extends Animal {
@Override
public void cry() {
System.out.println("汪汪汪、、、");
}
}
package d4_abstrsact;
public class Cat extends Animal{
@Override
public void cry() {
System.out.println("喵喵喵。。。");
}
}
package d4_abstrsact;
public class Text {
public static void main(String[] args) {
Cat c = new Cat();
Dog d = new Dog();
c.cry();
d.cry();
}
}
(3)应用场景
模板方法设计模式
解决方法中存在重复代码的问题
写法:
- 1.定义一个抽象类
- 2.在里面定义两个方法;
一个是模板方法:把相同的代码放里面去
一个是抽象方法:具体实现交给子类实现
package d5_abstract;
public class Text {
public static void main(String[] args) {
//目标:搞清楚抽象类的应用场景之一,经常用来设计模板方法设计模式
//场景 :学生,老师都要写一篇作文
//开头 结尾一样,正文自由发挥
Teacher t = new Teacher();
t.write();
}
}
package d5_abstract;
public abstract class People {
// 设计模板方式方法
//定义一个模板方法
public void write() {
System.out.println("\t\t\t\t\t《我的爸爸》");
//模板方法不清楚正文部分怎么写,但是它知道子类要去写
System.out.println(writeMain());
System.out.println("有这样的爸爸太好了");
}
public abstract String writeMain();
}
package d5_abstract;
public class Teacher extends People {
public String writeMain() {
return "也是非常厉害";
}
}
package d5_abstract;
public class Student extends People {
@Override
public String writeMain() {
return " 厉害";
}
}
建议 final关键字修饰模版方法 :
- 模板方法直接给对象使用,不能被子类重写
- 一旦子类重写了模板方法,模板方法就失效了
6.接口
(1)概述
java 提供了一个关键字interface ,用这个关键字可以定义一个特殊的结构:接口
接口中没有构造器和代码块之类的东西 ,接口也不可以创建对象。接口是被类实现(implements)的,实现接口的类称为实现类。
一个类可以实现多个接口(接口可以理解成干爹),实现类实现多个接口。必须重写完全部接口的全部抽象方法,否则实现类需要定义为抽象类
接口的好处:
弥补了类单继承的不足,一个类同时实现多个接口。(拓展功能)
让程序可以面向接口编程,这样程序员就可以灵活方便的切换各种业务实现
package d6_interface;
public class Text {
public static void main(String[] args) {
//目标:搞清楚使用接口的好处
Driver s = new A();
s.drive();
}
}
class A extends Student implements Driver {
@Override
public void drive(){
System.out.println("会开车");
}
}
class Student{}
interface Driver {
void drive();
}
interface Singer{
void sing();
}
(2)综合案例
需求:
请涉及一个班级学生的信息管理模块,学生的数据有:姓名,性别,成绩,
功能1:要求打印出全班学生的信息。功能2:要求打印出全班学生的平均成绩。
————————————————————————————————————————
以上业务的实现有多套方案。例如:
第一套方案能打印班级全部学生的信息,能打印班级全部学生的平均分。
第二套方案能打印出班级全部学生的信息(包括男女人数)。能打印班级全部学生的平均分(要求是去掉最高分,最低分)。
package d7_interface_demo;
import java.util.ArrayList;
public class student_mpl1 implements studentOperator {
@Override
public void printAllInfo(ArrayList<Student> students){
System.out.println("======全班全部学生信息======");
for (int i = 0; i < students.size(); i++) {
Student s = students.get(i);
System.out.println("姓名:"+s.getName());
System.out.println("性别:"+s.getSex());
System.out.println("成绩:"+s.getScore());
System.out.println("======================");
}
System.out.println("打印完毕");
}
@Override
public void printAverageScore(ArrayList<Student> students){
double allScore = 0.0;
for (int i = 0; i < students.size(); i++) {
Student s = students.get(i);
allScore += s.getScore();
}
System.out.println("平均分:"+(allScore/students.size()));
}
}
package d7_interface_demo;
import java.util.ArrayList;
public class student_mpl2 implements studentOperator{
@Override
public void printAllInfo(ArrayList<Student> students){
System.out.println("======全班全部学生信息======");
int count1 = 0;
int count2 = 0;
for (int i = 0; i < students.size(); i++) {
Student s = students.get(i);
System.out.println("姓名"+s.getName());
System.out.println("性别"+s.getSex());
if(s.getSex() == '男'){count1++;}else{count2++;}
System.out.println("成绩"+s.getScore());
System.out.println("======================");
}
System.out.println("男生人数:"+count1);
System.out.println("女生人数:"+count2);
System.out.println("班级总人数"+students.size());
System.out.println("打印完毕");
}
@Override
public void printAverageScore(ArrayList<Student> students){
double allScore = 0.0;
double max = students.get(0).getScore();
double min = students.get(0).getScore();
for (int i = 0; i < students.size(); i++) {
Student s = students.get(i);
allScore += s.getScore();
if(s.getScore() > max){max = s.getScore();}
if(s.getScore() < min){min = s.getScore();}
}
System.out.println("学生的最高分:"+max);
System.out.println("学生的最低分:"+min);
System.out.println("平均分:"+((allScore-max-min)/students.size()-2));
}
}
package d7_interface_demo;
import java.util.ArrayList;
public interface studentOperator {
void printAllInfo(ArrayList<Student> students);
void printAverageScore(ArrayList<Student> students);
}
package d7_interface_demo;
import java.util.ArrayList;
public class ClassManager {
private ArrayList<Student> students = new ArrayList<>();
private studentOperator stuopera = new student_mpl1();
//private studentOperator stuopera = new student_mpl2();
public ClassManager(){
students.add(new Student("陈平安",'男',88));
students.add(new Student("刘羡阳",'男',100));
students.add(new Student("顾璨",'男',90));
students.add(new Student("宁姚",'女',100));
}
//打印全班全部学生信息
public void printInfo(){
stuopera.printAllInfo(students);
}
//打印全班全部学生的平均分
public void printScore(){
stuopera.printAverageScore(students);
}
}
package d7_interface_demo;
public class Text {
public static void main(String[] args) {
//目标:完成班级学生信息管理的案例
ClassManager opera = new ClassManager();
opera.printInfo();
opera.printScore();
}
}
(3)接口的细节
JDK8后接口新增的三种方法(增强接口功能,便于系统维护)
package d8_jdk8;
public interface A {
//1.默认方法:必须使用default修饰,默认会被public修饰
//实例方法:对象访问 ,必须通过实现类
default void text1(){
System.out.println("默认方法");
text2();
}
//2.私有方法:必须使用private修饰
//jkk9后支持 //在接口中调用
private void text2(){
System.out.println("私有方法");
}
//3.静态方法:必须使用static修饰
//只能使用接口名来调用
public static void text3(){
System.out.println("静态方法");
}
}
接口的多继承
便于类去实现
接口的注意事项(了解)
- 一个接口继承多个接口,如果多个接口中存在方法签名冲突,则此时不支持多继承。
- 一个类实现多个接口,如果多个接口中存在方法签名冲突,则此时不支持多实现.
- 一个类,继承了父类,又同时实现了接口。父类中和接口中有同名的默认方法实现类会优先用父类的。
- 一个类实现了多个接口,多个接口中存在同名的默认方法可以不冲突,这个类重写该方法即可。
7.内部类
(1)内部类概述
内部类是类中的五大成分之一(成员变量,方法,构造器,内部类,代码块),一个类定义在另一个类的内部,这个类就是内部类
(2)成员内部类
类中的一个普通成员,类似前面学过的普通的成员变量,成员方法(注意访问特点)
注意事项:
1.jdk16后支持内部类创建静态成员变量
2.内部类创建对象的格式:外部类名.内部类名 对象名 = new 外部类 (...)new 内部类(...);
(3)静态内部类
有static修饰的内部类,属于外部类自己持有。
(4)局部内部类
局部内部类是定义在方法中,代码中,构造体等执行体(鸡肋语法)
(5)匿名内部类*
就是一种特殊的内部类;所谓匿名:指程序员不需要为这个类声明名字
使用场景: 通常作为一个参数传输给方法
实际应用场景:
package d2_inner; import javax.swing.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; public class Text4 { public static void main(String[] args) { //拓展:搞清楚匿名内部类在着真实开发中的使用场景 //GUI编程 //1.创建窗口 JFrame win = new JFrame("登录界面"); JPanel panel = new JPanel(); win.add(panel); JButton btn = new JButton("登录"); win.add(btn); // 给按钮绑定单击事件监听器 btn.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { JOptionPane.showMessageDialog(win,"欢迎"); } }); //最终的核心目的是:简化代码 win.setSize(400,400); win.setLocationRelativeTo(null); win.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); win.setVisible(true); } }
8.枚举
枚举是一种特殊类
(1)介绍
- 枚举类的第一行只能罗列一些名称,这些名称都是常量,并且每一个常量记住的都是枚举类的一个对象。
- 枚举类的构造器都是私有的(写与不写都只能是私有),因此枚举类对外不能创建对象。
- 枚举都是最终类,不可以被继承,枚举类中从第二行开始可以定义类的其他各种成员。
- 编译器为枚举类新增了几个方法,并且枚举类都是继承JAVA.long.Enum类。
package d3_enum;
public class Text {
public static void main(String[] args) {
//目标 认识枚举
A a1 = A.X ;
System.out.println(a1);
//枚举类提供一个一些额外的API
A[] as = A.values(); //拿到全部对象
A a3 = A.valueOf("Z");
System.out.println(a3.name());
System.out.println(a3.ordinal()); //索引
}
}
(2)应用场景
应用场景: 用来表示一组信息,然后作为参数进行传输
作为信息分类
9.泛型
(1)认识泛型
泛型:定义类,接口,方法时,同时声明了一个或者多个类型变量<E>,称为泛型类,泛型接口,泛型方法,统称为泛型
作用:泛型提供了在编译阶段约束所能操作的数据类型,并自动进行检查的能力,这样可以避免强制类型转换,及其可能出现的异常
泛型的本质:把具体的数据类型作为参数传给类型变量
(2)泛型类
package d5_generics;
public class List <E>{
private Object [] arr = new Object[10];
private int size;
public boolean add(E e){
arr[size++] = e;
return true;
}
public E get (int index){
return (E) arr[index];
}
}
(3)泛型接口
package d5_generics;
import java.util.ArrayList;
public interface Data<T> {
void add(T t);
ArrayList<T> getByName(String name);
}
泛型接口的类型变量建议使用大写英文字母
(4)泛型方法,泛型通配符,上下限
package d5_generics;
import java.util.ArrayList;
public class Text3 {
public static void main(String[] args) {
//目标:掌握泛型方法的定义和使用
String rs = test("java");
Dog d = test(new Dog());
System.out.println(d);
}
//泛型方法
public static <T> T test (T t){
return t;
}
//使用extends限制输入类型 是car或者car的子类
public static <T extends car > void go(ArrayList<T> car){
}
//? 通用符 使用泛型可以代表一切类型 一样可以限制 ?extends car(上限) ?super car(下限)
public static void go1(ArrayList<? extends car> car){
}
}
(5)注意事项
擦除问题
泛型是工作在编译阶段的,一旦程序编译成class文件。Class文件中就不存在泛型了,这就是泛型擦除。(底层还是基于Object类型)
泛型不支持基本数据类型。只能支持对象类型(引用数据类型)。
学习时间:2024.8.4