JAVA学习第一阶段模块二

news/2025/3/19 14:41:13/

模块二 Java面向对象

类和对象

类和对象及引用

对象主要指现实生活中客观存在的实体,在Java语言中对象体现为内存空间中的一块存储区域。

类的定义方法

class 类名{类体;
}class Person{  //类名命名:通常情况下,当类名由多个单词组成时,要求每个单词首字母都要大写}

成员变量的定义

class Person{//成员变量命名:当成员变量由多个单词组成时,通常要求从第二个单词起每个单词的首字母大写 。String name; 
}

对象的创建

new Person();  //创建改类的对象,这个创建的过程叫类的实例化
  1. 当一个类定义完毕后,可以使用new关键字来创建该类的对象,这个过程叫做类的实例化。
  2. 创建对象的本质就是在内存空间的堆区申请一块存储区域, 用于存放该对象独有特征信息。

引用的定义

Person p = new Person();
p.name = "张飞";
System.out.println(p.name);
  1. 使用引用数据类型定义的变量叫做引用型变量,简称为"引用"。
  2. 引用变量主要用于记录对象在堆区中的内存地址信息,便于下次访问。

成员变量的初始值

类型初始值
byte、short、int、long、float、double、char0
booleanfalse
引用类型null

案例题目

编程实现Point类的定义,特征有:横纵坐标(整数),要求在main方法中声明Point类型的引用指向Point对象并打印特征,然后将横纵坐标修改为3和5后再次打印

public class Point{int x;int y;public static void main(String[] args){System.out.println("横坐标为" + x + "纵坐标为" + y);//输出横坐标为0纵坐标为0Point p = new Point();p.x = 3;p.y = 5;System.out.println("横坐标为" + x + "纵坐标为" + y); //输出横坐标为3纵坐标为5}
}

成员方法

成员方法的定义

class Person(){void run(){ //成员方法System.out.println("跑步");}void runFast(){ //当成员方法名由多个单词组成时,要求从第二个单词起每个单词的首字母大写。System.out.println("快速跑步");}
}

返回值类型

  • 基本类型(byte、short、int、long、float、double、boolean、char)
  • 引用类型(String、Person等)
  • 无返回值类型 void

无参方法

class Person(){void run(){ // 无参无返回值System.out.println("跑步" + m + "米");}String run(){ // 无参有返回值return "跑步";}
}

有参方法

class Person(){void run(int m){ // 有参无返回值System.out.println("跑步" + m + "米");}String run(int m){ // 有参有返回值String s = "跑步" + m + "米";return s;}
}

方法和封装

构造方法

与类名名称完全相同并且没有返回值类型,void也不能有

class 类名{类名(形参列表){构造方法体;}
}
class Person{Person(){ //构造方法构造方法体;}
}
  • 默认构造方法:编译器会自动添加一个空的构造方法 -->Person(){}
  • 如果类中出现了构造方法,编译器将不会提供任何构造方法
  • 创建类的对象时会默认调用构造方法
public class Person{Person(){System.out.println("构造方法");}public static void main(String[] args){Person p = new Person(); // 输出“构造方法”}
}

成员变量初始化

public class Person{String name;int agePerson(String s, int a){age = a;name = s;}public static void main(String[] args){Person p = new Person("张飞", 30); //输出姓名为张飞年龄为30System.out.println("姓名为" + p.name + "年龄为" + p.age);}
}

方法重载

方法名称相同,参数列表不同,这样的方法之间构成重载关系(Overload)

public class Person{void run(){System.out.println("run()");}void run(int a){    //参数个数不同。可以构成重载System.out.println("run(int)");}void run(int a, int b){ //参数个数不同。可以构成重载System.out.println("run(int, int)");}void run(int a, double b){ //参数类型不同。可以构成重载System.out.println("run(int, double)");}void run(double b, int a){ //参数顺序不同。可以构成重载System.out.println("run(double, int)");}/* int run(double b, int a){ //参数返回值不同。不可以构成重载System.out.println("run(double, int)");} */public static void main(String[] args){Person p = new Person();p.run();  //输出run()p.run(1); //输出run(int)p.run(1, 2); //输出run(int, int)p.run(1, 3.14); //输出run(int, double)p.run(3.14, 1); //输出run(double, int)}
}

重载的实际意义

调用者只需要记住一个方法名,通过参数不同控制不同版本,实现不同的功能;

this关键字

  • 如果在构造方法中出现了this关键字,则代表当前正在构造的对象
  • 如果在成员方法中出现了this关键字,则代表当前正在调用的对象
  • this关键字本质上就是当前类类型的一个引用
public class ThisTest {ThisTest() {//this代表当前正在构造的对象System.out.println("构造方法 this = " + this);}void show() {//this代表当前正在调用的对象System.out.println("成员方法 this = " + this);}public static void main(String[] args) {ThisTest tt = new ThisTest();  //构造方法 this = ThisTest@6bf256fatt.show();  //成员方法 this = ThisTest@6bf256faSystem.out.println("main方法 tt = " + tt); //main方法 tt = ThisTest@6bf256fa}
}

在构造方法、成员方法中访问成员变量时,编译器会加上==this.==的前缀,当不同的对象调用同一个方法时,由于调用的对象不同导致this关键字不同,从而使this.方式访问的结果不同。

就近原则

  • 当局部变量与成员变量名相同时,在方法体内会优先使用局部变量
  • 如果希望使用成员变量,需要在成员变量前面加==this.==关键字
public class Person{String name;int agePerson(String name, int age){this.name = name;this.age = age;}public static void main(String[] args){Person p = new Person("张飞", 30); //输出姓名为null,年龄为0System.out.println("姓名为" + p.name + "年龄为" + p.age); //实际使用的是形参非实参}
}

使用this调用构造方法

不能无参构造器调用有参构造器且有参构造器调用无参构造器,会造成递归构造器调用

// 造成递归构造器调用报错
public class Person{String name;int agePerson(){this("张飞"30); // 无参构造器调用有参构造器System.out.println("无参构造");}Person(String name, int age){this(); // 有参构造器调用无参构造器this.name = name;this.age = age;System.out.println("有参构造");}public static void main(String[] args){Person p = new Person(); //输出有参构造System.out.println("姓名为" + p.name + "年龄为" + p.age); //实际使用的是形参非实参}
}

空指针异常

public class Person{String name;int agePerson(){}void run(){System.out.println("跑步");}public static void main(String[] args){Person p = null; //空的引用,无内存空间p.run(); //NullPointException}
}

阶乘

for循环方式实现

//计算1~n的阶乘
public class FactorialTest {int factorial(int n) {int sum = 1;for (int i = 1; i < n; i++) {sum *= i;}return sum;}public static void main(String[] args) {FactorialTest factorialTest = new FactorialTest();int sum = factorialTest.factorial(10);System.out.println(sum);}
}

n*(n-1)的阶乘

//计算1~n的阶乘
public class FactorialTest {int factorial(int n) {if (1 == n){return n;}return n*factorial(n-1); //调用自身}public static void main(String[] args) {FactorialTest factorialTest = new FactorialTest();int sum = factorialTest.factorial(10);System.out.println(sum);}
}

递归基本概念:自身调用自身

费式数列

递归方式实现
public class FeiShiTest {int show(int n) {int num = 0;if (n == 1 || n == 2) {return 1;}
//        num += show(n - 1) + show(n - 2);
//        return num;return show(n - 1) + show(n - 2);}public static void main(String[] args) {FeiShiTest fst = new FeiShiTest();int num = fst.show(8);System.out.println(num);}
}

***递归计算量大会影响性能***:调用方法不停的申请栈帧,消耗性能,尽量使用递推

递推方式实现
public class FeiShiTest {int show(int n) {int ia = 1;int ib = 1;if (n == 1 || n == 2) {return 1;}for (int i = 3; i <= n; i++) {int ic = ia + ib;ia = ib;ib = ic;}return ib;}public static void main(String[] args) {FeiShiTest fst = new FeiShiTest();int num = fst.show(8);System.out.println(num);}
}

封装

  • 通常情况下可以在测试类给成员变量赋值一些合法但不合理的数值,无论是编译阶段还是运行阶段都不会报错或者给出提示,此时与现实生活不符。
  • 为了避免上述错误的发生,就需要对成员变量进行密封包装处理,来隐藏成员变量的细节以及保证成员变量数值的合理性,该机制就叫做封装。

private关键字

public class Student {private int id; //成员变量私有化private String name; //成员变量私有化public int getId() { //提供get、set方法访问和设置成员变量return id;}public void setId(int id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}
}

案例题

编程实现学生信息的录入和打印

public class StudentTest2 {public static void main(String[] args) {System.out.println("请输入学生数量:");Scanner sc = new Scanner(System.in);int num = sc.nextInt();Student[] students = new Student[num];for (int i = 0; i < num; i++) {System.out.println("请输入第" + (i + 1) + "个学生姓名:");String name = sc.next();System.out.println("请输入第" + (i + 1) + "个学生学号:");int id = sc.nextInt();students[i] = new Student(id, name);}System.out.println(Arrays.toString(students));}
}

static关键字和继承

static关键字

成员变量从对象层提升为类层级,整个类只有一份并被所有对象共享,该成员变量随着类的加载准备就绪,与是否创建对象无关

public class Person{private String name;private int id;private static String country;  // 静态成员变量 被所有对象共享public static void show(){System.out.println("静态show()方法");}
}

可以使用==引用.的方式调用,但更推荐使用类名.==的方式调用

Person p = new Person();
p.country;
Person.country; //推荐使用
Person.show();
  • 在非静态成员方法中,既能访问静态成员变量也能访问非静态成员变量
public class StaticTest {private int cnt = 1; // 隶属于对象层级,也就是每个对象都拥有独立的一份private static int snt = 2; // 隶属于类层级,也就是所有对象都共享同一份// 自定义非静态的成员方法  需要使用引用.的方式访问public void show() {// 打印1System.out.println("cnt = " + this.cnt); // 打印2 静态成员被所有对象共享,this关键字可以省略System.out.println("snt = " + this.snt); public static void main(String[] args) {StaticTest st = new StaticTest();st.show(); }    
}
  • 静态成员方法中,只能访问静态的成员变量,不能访问非静态的成员变量,因为非静态的成员变量需要使用引用去调用,使用==类名.==的方式调用时没有引用,无法访问非静态成员变量
public class StaticTest {private int cnt = 1; // 隶属于对象层级,也就是每个对象都拥有独立的一份private static int snt = 2; // 隶属于类层级,也就是所有对象都共享同一份public static void test() {// StaticTest st = new StaticTest();// 报错   静态成员方法中没有this关键字,因为是可以通过类名.方式调用的System.out.println("cnt = " + cnt); // 打印2 System.out.println("snt = " + snt);}public static void main(String[] args) {StaticTest.test(); //这里调用的使用还没有引用}
}

构造块和静态代码块

构造块

  • 在类体中直接使用=={}==括起来的代码块
  • 当需要执行构造方法体之前做一些准备工作时,则将准备工作的写在构造块中
  • 构造块执行顺序 > 构造方法
  • 每创建一个对象都会执行一次构造块
public class BlockTest {{System.out.println("构造块");}public BlockTest(){System.out.println("===构造方法体");}public static void main(String[] args) {BlockTest bt = new BlockTest();//输出构造块//输出===构造方法体}
}

静态代码块

  • 使用static关键字修饰的构造块
  • 会随着类的加载准备就绪,只执行一次!!
  • 加载顺序静态代码块 > 构造块 > 构造方法
  • 需要执行代码块之前随着类的加载做一些准备工作时,编写到静态代码块里
public class BlockTest {{System.out.println("构造块");}static {System.out.println("###静态代码块");}public BlockTest() {System.out.println("===构造方法体");}public static void main(String[] args) {BlockTest bt = new BlockTest();BlockTest bt2 = new BlockTest();//###静态代码块 (只加载一次)//构造块//===构造方法体//构造块//===构造方法体}
}

单例模式(重点)

  • 一个类对外只提供一个对象

饿汉式

  • 不论是否被调用都会初始化一个对象(线程安全,推荐使用)
public class Singleton {private Singleton(){  //私有化构造方法,无法使用new创建对象}private static Singleton sin = new Singleton(); //私有静态对象,随着类加载只生成一个对象public static Singleton getInstance(){ //只能通过Singleton.getInstance获取对象return sin;}
}

懒汉式

  • 当被调用时再去创建对象(线程不安全)
public class Singleton {private Singleton() {}private static Singleton sin = null; //初始设置引用为nullpublic static Singleton getInstance() {if (sin == null) {        //被调用时发现引用为null再创建对象sin = new Singleton();}return sin;  //不为null直接返回,为null则创建一个对象再返回}
}

继承

基本概念

  • 当多个类有共同的特征或者特性时,提取成为一个公共类,让其他子类继承

  • 使用extends关键字来表示继承关系

public class Person{ //基类}
class Worker extends Person{ //子类}
  • 使用继承提高了代码的可复用性可维护性扩展性,是多态的前提条件
  • 子类不能继承父类的构造方法私有方法,但私有成员变量可以被继承,只是不能直接访问
  • 子类默认调用父类的无参构造方法,来初始化从父类中继承的成员变量,相当于在子类构造方法第一行加了super()(编译器自动添加,无需手动编写)
  • 子类的有参构造方法会调用父类的有参构造方法

方法重写(Override)

  • 当父类中继承下来的方法不满足子类需求,重新写一个方法覆盖父类中的原始方法,这种方式叫做方法的重写
  • 使用@Override注解标注
  • 重写的方法名必须与父类中方法名称相同
  • 重写的方法返回值类型可以是父类父类的子类类型(java5之后支持)
  • 重写方法的权限修饰符不能变小,可以相同或者变大(如父类为public,子类不能为private)
  • 重写的方法不能抛出更大的异常
public class Person{ //基类public void show(){System.out.println("show人类");}
}
class Worker extends Person{ //子类@Override  //标注/注解 是对父类方法重写的说明,若没有则造成编译报错public void show(){System.out.println("show工人");}
}

构造块和静态代码块的考点

  • 先执行父类的静态代码块,再执行子类的静态代码块。
  • 执行父类的构造块,执行父类的构造方法体。
  • 执行子类的构造块,执行子类的构造方法体。

访问控制

修饰符本类同一个包中的类子类其他类
private可以访问不能访问不能访问不能访问
protected可以访问可以访问可以访问不能访问
public可以访问可以访问可以访问可以访问
默认可以访问不能访问不能访问不能访问

final关键字

  • final修饰类体,该类不可被继承,主要防止滥用继承
public final class FinalTest{}
  • final修饰成员方法体,该方法不可以被重写
public  class FinalVoidTest{public final void show(){}
}
  • final修饰成员变量,要求成员变量必须初始化,且不可被改变

    Thread类中MAX_PRIORITY

public class FinalMemberTest{private final int cnt = 1; //直接初始化{cnt = 2;  //构造块中初始化}public FinalMemberTest(){cnt = 3; //构造方法中初始化}
}
  • 设置常量
public static final double PI = 3.14

多态和特殊类

多态

  • 子类未重写父类方法,调用的是父类的方法(父类方法不满足子类需求)
public class Father { //父类public void show() {System.out.println("我是爸爸");}}
public class Son extends Father { //子类@Overridepublic void show() {super.show();System.out.println("我是儿子");}public void goToSchool(){System.out.println("儿子上学");}public static void main(String[] args) {Father father = new Son(); //父类类型引用指向子类对象father.show(); //打印 我是儿子}
}
  • 编译阶段调用父类show()方法,运行阶段调用子类show()方法

类型转换

  • 父类类型引用调用子类独有方法,父类转子类–>大转小需要强转
public static void main(String[] args) {Father father = new Son(); //父类类型引用指向子类对象((Son)father).goToSchool(); //打印 儿子上学
}
  • 非继承关系强制转换–>ClassCastException 类型转换异常(运行阶段异常)
  • 使用instanceof关键字判断对象是否为类的实例
if(father instanceof Son){((Son)father).goToSchool();
}else{...
}

抽象类

  • abstract 关键字
public abstract class AbstractTest{}
  • 不能实例化,也就是不能创建对象
  • 可以有成员方法、成员变量、构造方法
  • 可以有抽象方法,也可以没有抽象方法
public abstract class AbstractTest{private int x;public AbstractTest(){}public int getX(){return x;}public static void main(String[] args){AbstractTest at = new AbstractTest(); //报错}
}
  • 抽象类不能创建对象,由于抽象类中可能会有抽象方法,为了防止抽象方法被调用,禁止创建抽象类的对象
  • 抽象类的意义不在于创建对象而在于被继承(模板)
  • 继承抽象类必须重写抽象方法,否则该类也要变成抽象类

笔试考点

  • private和abstract关键字不能共同修饰一个方法
//子类不能继承父类构造方法、私有方法,无法被子类重写,无意义
private abstract void show(); 
  • final和abstract关键字不能共同修饰一个方法
//final不能被重写只能被继承;abstract只能被重写后使用,相互矛盾
public final abstract void show(); 
  • static和abstract关键字不能共同修饰一个方法
//abstract类不能创建对象,使用static之后就可以使用类名.访问,不允许直接调用抽象方法
public static abstract void show(); 

接口

  • 接口里面的成员变量只能是常量
public interface InterfaceTest1{/*public static final*/ int CNT = 1;  //里面只能有常量
}
  • 接口内方法必须是抽象方法(java1.9之后接口内允许有私有方法)
public interface InterfaceTest2{private void show1(); //允许/*public abstract*/ void show2(); //建议写上提高代码可读性 public void show3(); //不允许 
}
  • 无构造方法
  • 可以多实现(implements)
public class InterfaceTest3 implements InterfaceTest2,InterfaceTest1{}
  • 类实现接口内抽象方法,必须也实现该接口父类的抽象方法

类和接口的关系

名称关键字关系
类和类extends单继承
接口和接口extends支持多继承
类和接口implements多实现

接口和抽象类的区别

  • 定义方式:接口是使用interface关键字;抽象类是使用abstract class关键字
  • 继承方式:实现接口使用implements关键字,而且可以多实现;抽象类使用extends关键字,只能单继承
  • 方法:抽象类中可以有成员方法;接口中只能有抽象方法
  • 子类:抽象类中的方法子类不是必须重写;接口中的方法子类必须重写(java8之前的版本)
  • 从java8开始增加新特性,接口中可以出现非抽象方法和静态方法,单非抽象方法需要用default关键字修饰
public interface Hunter {public default void show(){} //仅仅是接口中的默认功能,子类可以自由选择是否重写public static void show1(){} //静态方法属于类层级,可以用类名.的方式调用
}

特殊类

内部类

普通内部类

  • 将一个类定义在另一个类的类体内
  • 和普通类一样可以拥有成员变量、成员方法、构造方法
  • 和普通类一样可以使用final、abstract关键字修饰
  • 创建内部类对象需要使用外部类对象来创建
  • 可以使用private和protected关键字修饰
  • 如果使用内部类访问外部类与本类
public class NormalOuter {private int cnt = 3;public class NormalInner {private int cnt = 2;public void show1(){System.out.println(this.cnt);}public void show2(){System.out.println(NormalOuter.this.cnt);}}public static void main(String[] args) {//声明NormalOuter类型引用指向Normal对象NormalOuter no = new NormalOuter();//使用NormalOuter类型引用指向内部类对象NormalOuter.NormalInner nn = no.new NormalInner();//输出2nn.show1();//输出3nn.show2();}
}

静态内部类

  • 使用static关键字修饰的内部类,隶属于类层级
  • 静态内部类不能访问外部类非静态的成员
public class StaticOuter {private int cnt = 1;private static int snt = 2;public static class StaticInner {private int cnt = 3;private static int snt = 4;public void show(int cnt) {System.out.println("cnt = " + cnt); //就近原则,打印的是形参System.out.println("内部类cnt = " + this.cnt); //打印3,内部类的成员变量System.out.println("内部类静态snt = " + snt); //打印4,内部类的静态成员变量System.out.println("外部类cnt = " + new StaticOuter().cnt); // 打印1,外部类的成员变量System.out.println("外部类cnt = " + cnt); //报错,无法直接访问System.out.println("外部类静态snt = " + StaticOuter.snt); //打印2,外部类的静态成员变量}}
}

局部内部类

  • 将一个类定义在方法体内
  • 只能在该方法的内部使用
  • 可以在方法体的内部直接创建对象
  • 不能使用访问控制符(public、private)
  • 可以使用外部方法的局部变量,但必须是使用final修饰的
public class AreaOuter {private int cnt = 1;public void show() {// 定义一个局部变量进行测试,从Java8开始默认理解为final关键字修饰的变量// 虽然可以省略final关键字,但建议还是加上final int ic = 4;// 定义局部内部类,只在当前方法体的内部好使    拷贝一份class AreaInner {private int ia = 2;public AreaInner() {System.out.println("局部内部类的构造方法!");}public void test() {int ib = 3;System.out.println("ia = " + ia); // 2System.out.println("cnt = " + cnt); // 1//ic = 5;  ErrorSystem.out.println("ic = " + ic); // 4}}// 声明局部内部类的引用指向局部内部类的对象AreaInner ai = new AreaInner();ai.test();}
}

回调模式

  • 如果一个方法的形参是接口类型,在调用该方法时要创建一个实现了该接口类型的对象,并且会调用到实现了该接口定义的方法。
public interface AnonymousInterface {void show();
}
public class AnonymousInterfaceImpl implements AnonymousInterface {@Overridepublic void show() {System.out.println("这里是AnonymousInterfaceImpl");}
}
public class AnonymousInterfaceTest {public void show(AnonymousInterface ai){}public static void main(String[] args) {AnonymousInterfaceTest anonymousInterfaceTest = new AnonymousInterfaceTest();//传递实现类 多态的一种表现形式anonymousInterfaceTest.show(new AnonymousInterfaceImpl()); }
}

匿名内部类

public class AnonymousInterfaceTest {public void show(AnonymousInterface ai){}public static void main(String[] args) {AnonymousInterfaceTest anonymousInterfaceTest = new AnonymousInterfaceTest();//匿名内部类anonymousInterfaceTest.show(new AnonymousInterface() {@Overridepublic void show() {System.out.println("这里是匿名内部类!");}});//java8 Lambda表达式anonymousInterfaceTest.show(()->{System.out.println("这里是Lambda表达式替代匿名内部类");});}
}

枚举

  • 使用public static final修饰常量比较繁琐,使用enum关键字来定义枚举类型取代常量
  • 从java5开始,是一种引用数据类型
  • 枚举值是当前类的引用类型,默认使用private static final修饰,因此采用==枚举类型.==的方式调用
  • 枚举类型可以自定义构造方法,但访问控制符必须是private(可省略)
public enum DirectionEnum {UP("向上"),DOWN("向下"),LEFT("向左"),RIGHT("向右");private String desc;/*private*/ DirectionEnum(String desc) {this.desc = desc;}public String getDesc() {return desc;}public static void main(String[] args) {//输出 向下System.out.println(DirectionEnum.DOWN.getDesc());}
}
public class DirectionTest {public static void test(DirectionEnum directionEnum){switch (directionEnum){case UP:System.out.println("向上");break;case DOWN:System.out.println("向下");break;case LEFT:System.out.println("向左");break;case RIGHT:System.out.println("向右");break;default:System.out.println("你好");}}public static void main(String[] args) {DirectionTest.test(DirectionEnum.DOWN);}
}
  • 所有的枚举类都继承自java.lang.Enum类,不能再继承其他类,但是可以实现接口

常用方法

方法作用
static T[] values()返回当前枚举类所有对象
String toString()返回当前枚举类对象的名称
int ordinal()返回枚举对象在枚举类中的索引值
static T valueOf(String str)将参数指定的字符串名转为当前枚举类的对象
int compareTo(E o)使用当前枚举对象和传入的枚举对象比较顺序(返回传入的枚举对象索引位置-当前枚举对象索引位置)
public class DirectionTest {public static void test(DirectionEnum directionEnum){switch (directionEnum){case UP:System.out.println("向上");break;case DOWN:System.out.println("向下");break;case LEFT:System.out.println("向左");break;case RIGHT:System.out.println("向右");break;default:System.out.println("你好");}}public static void main(String[] args) {DirectionEnum[] values = DirectionEnum.values();//java.lang.IllegalArgumentException: No enum constant com.miaoxun.study01.DirectionEnum.STAND//DirectionEnum directionEnum = DirectionEnum.valueOf("STAND"); //Error//将字符串转换为枚举对象DirectionEnum directionEnum1 = DirectionEnum.valueOf("UP");for (int i = 0; i < values.length; i++) {//打印枚举值:UP 当前索引值为:0System.out.println("枚举值:" + values[i].toString() + " 当前索引值为:" + values[i].ordinal());//与DOWN比较结果为-1System.out.println("与" + directionEnum1.toString() + "比较结果为" + values[i].compareTo(directionEnum1));}System.out.println(Arrays.toString(values));//打印[UP, DOWN, LEFT, RIGHT]System.out.println(Arrays.toString(values));}
}
  • 枚举类实现接口,实现接口定义的成员方法可以整个类重写一次,也可以每个枚举对象单独全部重写(匿名内部类写法)
public enum DirectionEnum implements DirectionInterface {UP("向上") {@Overridepublic void show() {System.out.println("专属于向上的show()");}},DOWN("向下"){@Overridepublic void show() {System.out.println("专属于向下的show()");}},LEFT("向左"){@Overridepublic void show() {System.out.println("专属于向左的show()");}},RIGHT("向右"){@Overridepublic void show() {System.out.println("专属于向右的show()");}};private String desc;DirectionEnum(String desc) {this.desc = desc;}public String getDesc() {return desc;}public static void main(String[] args) {System.out.println(DirectionEnum.DOWN.getDesc());}//    @Override
//    public void show() {
//        System.out.println("整个枚举类公用一个show()方法");
//    }
}

注解

  • 从java5开始引入的引用数据类型(特殊的接口)
  • 自定义注解默认继承java.lang.annotation.Annotation接口
  • 通过**@+注解名称**的方式可以修饰包、类、成员方法、成员变量、构造方法、参数、局部变量的声明等
  • 若一个注解中没有任何的成员,则被成为标记注解/标识注解
public @interface AnnoTest {}
@AnnoTest
public class Test{}
  • 注解中没有成员方法,只有成员变量,以无形参的形式来声明,方法名=成员变量名,返回值=成员变量类型
  • 类型只能是八种基本数据类型、String类型、Class类型、enum类型、Annotation类型
public @interface AnnoTest {public String value(); //声明一个String类型的成员变量,名字为valuepublic String name();public DirectionEnum direction();
}
//无默认值必须要给成员赋值
@AnnoTest(value = "123", name = "mm", direction = DirectionEnum.UP)
public class Test{}
  • 注解内的成员使用default给定初始值,使用注解可以不给成员赋值
public @interface AnnoTest {public String value() default "321"; //声明一个String类型的成员变量,名字为valuepublic String name()  default "ll";public DirectionEnum direction() default DirectionEnum.UP;
}@AnnoTest()
public class Test{}

元注解

  • 元注解是可以注解到注解上的注解,是一种基本注解le
  • 主要有==@Retetion、@Documented、@Target、@Inherited、@Repeatable==
@Retetion
  • 主要作用于一个注解上,说明该注解的生命周期
  • RetentionPolicy.SOURCE 注解只在源码阶段保留,在编译器进行编译时它将被丢弃忽视。
  • RetentionPolicy.CLASS 注解只被保留到编译进行的时候,它并不会被加载到JVM 中,默认方式。
  • RetentionPolicy.RUNTIME 注解可以保留到程序运行的时候,它会被加载进入到JVM 中,所以在程序运行时可以获取到它们。
  • RetentionPolicy是一个enum类型,有SOURCE、CLASS、RUNTIME三个枚举值
//@Retention(RetentionPolicy.SOURCE) //表示下面的注解在源代码中有效
//@Retention(RetentionPolicy.CLASS) //表示下面的注解在编译时有效
//@Retention(RetentionPolicy.RUNTIME) //表示下面的注解在程序运行时有效
public @interface AnnoTest {public String value() default "321"; //声明一个String类型的成员变量,名字为valuepublic String name()  default "ll";public DirectionEnum direction() default DirectionEnum.UP;
}
@Documented
  • 主要作用于一个注解上,加上注解后文档内可以看到该注解,否则看不到
@Documented
public @interface AnnoTest {public String value() default "321"; //声明一个String类型的成员变量,名字为valuepublic String name()  default "ll";public DirectionEnum direction() default DirectionEnum.UP;
}
@Target
  • 用于指定被修饰的注解能用于哪些元素的修饰
  • ElementType 枚举
枚举值用处
ElementType.ANNOTATION_TYPE可以给注解注解
ElementType.CONSTRUCTOR可以给构造方法注解
ElementType.FIELD可以给成员变量注解
ElementType.LOCAL_VARIABLE可以给局部变量注解
ElementType.METHOD可以给方法注解
ElementType.PACKAGE可以给包注解
ElementType.PARAMETER可以给方法内的参数注解
ElementType.TYPE可以给类型注解,如类、接口、枚举
@Target({ElementType.ANNOTATION_TYPE,ElementType.CONSTRUCTOR,ElementType.METHOD})
public @interface AnnoTest {public String value() default "321"; //声明一个String类型的成员变量,名字为valuepublic String name()  default "ll";public DirectionEnum direction() default DirectionEnum.UP;
}
@Inherited
  • 如果一个父类被使用@Inherited注解,且子类没有被注解,则继承父类的注解
@Repeatable
  • Repeatable(可重复的)

  • 一个注解描述多个角色

@Target(ElementType.TYPE_USE)
public @interface ManTypes {ManType[] value();
}
@Repeatable(value = ManTypes.class)
public @interface ManType {String value();
}
@ManType(value = "职工")
@ManType(value = "超人")
//@ManTypes({@ManType(value = "职工"), @ManType(value = "超人")})
public class Test{}

作业

  1. 编程实现以下需求:

定义一个长度为[16][16]的整型二维数组并输入或指定所有位置的元素值,分别实现二维数组中所有行和所有列中所有元素的累加和并打印。

再分别实现二维数组中左上角到右下角和右上角到左下角所有元素的累加和并打印。

/*** @author miaoxun* 编程实现以下需求:* 定义一个长度为[16][16]的整型二维数组并输入或指定所有位置的元素值,* 分别实现二维数组中所有行和所有列中所有元素的累加和并打印。* 再分别实现二维数组中左上角到右下角和右上角到左下角所有元素的累加和并打印。*/
public class Homework1 {public static void main(String[] args) {//定义一个长度为[16][16]的整型二维数组int[][] arr = new int[16][16];//定义局部变量统计所有元素的累加和int sum = 0;//定义局部变量统计二维数组中左上角到右下角的元素累加和int leftToRightSum = 0;//定义局部变量统计二维数组中左上角到右下角的元素累加和int rightToLeftSum = 0;for (int i = 0; i < arr.length; i++) {for (int j = 0; j < arr[i].length; j++) {//指定所有位置的元素值arr[i][j] = j;System.out.print(arr[i][j]);//计算所有元素的累加和sum += arr[i][j];//计算二维数组中左上角到右下角的元素累加和if (j == i) {leftToRightSum += arr[i][j];}//计算二维数组中右上角到左下角的元素累加和if (j == (arr.length - i)){rightToLeftSum += arr[i][j];}}System.out.println();}System.out.println("所有元素求和的值为:" + sum);System.out.println("二维数组中左上角到右下角的元素累加和为:" + leftToRightSum);System.out.println("二维数组中右上角到左下角的元素累加和为:" + rightToLeftSum);}
}
  1. 编程实现控制台版并支持两人对战的五子棋游戏。

    (1)绘制棋盘 - 写一个成员方法实现

    (2)提示黑方和白方分别下棋并重新绘制棋盘 - 写一个成员方法实现。

    (3)每当一方下棋后判断是否获胜 - 写一个成员方法实现。

    (4)提示: 采用二维数组来模拟并描述棋盘,棋盘如下:

import java.util.Scanner;/*** @author miaoxun* 编程实现控制台版并支持两人对战的五子棋游戏。*/
public class Homework2 {/*** 第一步:使用二维数组绘制五子棋盘** @return 返回五子棋盘二维数组*/public char[][] drawChessboard() {char[] arr = {' ', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};char[][] chessboard = new char[17][17];for (int i = 0; i < chessboard.length; i++) {for (int j = 0; j < chessboard[i].length; j++) {if (0 == i) {chessboard[i] = arr;} else if (0 == j) {chessboard[i][j] = arr[i];} else {chessboard[i][j] = '+';}}}return chessboard;}/*** 下棋方法*/public void playChess() {Scanner scanner = new Scanner(System.in);//定义退出循环标志位boolean flag = true;//定义数字达成两个人交替下棋int num = 0;char[][] chessboard = drawChessboard();char white = '⚪';char black = '⚫';while (flag) {if (num % 2 == 0) {System.out.println("请输入棋子的坐标,白棋:");//定义输入的横坐标int x = scanner.nextInt();//定义输入的纵坐标int y = scanner.nextInt();//判断是否走出棋盘外if (x <= 0 || x >= 17 || y <= 0 || y >= 17) {System.out.println("输入坐标不正确,请重新输入");continue;} else if (chessboard[x][y] != '+') { //判断是否已有棋子System.out.println("该处已有棋子,请重新下棋");continue;}chessboard[x][y] = white;//判断如果一方获胜则退出循环 程序结束if (isWin(chessboard)) {System.out.println("game over 白棋获胜!");flag = false;}} else {System.out.println("请输入棋子的坐标,黑棋:");//定义输入的横坐标int x = scanner.nextInt();//定义输入的纵坐标int y = scanner.nextInt();//判断是否走出棋盘外if (x <= 0 || x >= 17 || y <= 0 || y >= 17) {System.out.println("输入坐标不正确,请重新输入");continue;} else if (chessboard[x][y] != '+') { //判断是否已有棋子System.out.println("该处已有棋子,请重新下棋");continue;}chessboard[x][y] = black;//判断如果一方获胜则退出循环if (isWin(chessboard)) {System.out.println("game over 黑棋获胜!");flag = false;}}for (int i = 0; i < chessboard.length; i++) {for (int j = 0; j < chessboard[i].length; j++) {System.out.print(chessboard[i][j] + "  ");}System.out.println();}num++;}}/*** 判断是否已经获胜** @param chessboard 棋局现状* @return true:已获胜  false:未获胜*/public boolean isWin(char[][] chessboard) {char empty = '+';//设置棋子连珠数量int count = 1;//全盘扫描是否有符合条件的for (int i = 1; i < chessboard.length; i++) {for (int j = 1; j < chessboard[i].length; j++) {//横向判断 x(纵坐标)不变y(横坐标)向左右查询各4个for (int k = 1; k <= 4; k++) {//判断是否已经出界,且元素不是空值if ((j + k) <= chessboard.length && (j - k) > 0 && (chessboard[i][j] != empty)) {//如果左右查询4个发现是相同的棋子则count++if (chessboard[i][j] == chessboard[i][j + k] || chessboard[i][j] == chessboard[i][j - k]) {count++;//判断如果5子连珠则return true 停止程序游戏结束if (count == 5) {return true;}}}}//不满足上一条件重新设置count的值count = 1;//纵向判断 y(横坐标)不变x(纵坐标)向左右查询各4个for (int k = 1; k <= 4; k++) {//判断是否已经出界,且元素不是空值if ((i + k) <= chessboard.length && (i - k) > 0 && (chessboard[i][j] != empty)) {//如果上下查询4个发现是相同的棋子则count++if (chessboard[i][j] == chessboard[i + k][j] || chessboard[i][j] == chessboard[i - k][j]) {count++;//判断如果5子连珠则return true 停止程序游戏结束if (count == 5) {return true;}}}}//不满足上一条件重新设置count的值count = 1;//撇方向判断 x(纵坐标)加1 y(横坐标)减1/ x(纵坐标)减1 y(横坐标)加1查询各4个for (int k = 1; k <= 4; k++) {//判断是否已经出界,且元素不是空值if ((i + k) <= chessboard.length && (j - k) > 0 && (i - k) > 0 && (j + k) <= chessboard.length && (chessboard[i][j] != empty)) {//如果撇方向查询4个发现是相同的棋子则count++if (chessboard[i][j] == chessboard[i + k][j - k] || chessboard[i][j] == chessboard[i - k][j + k]) {count++;//判断如果5子连珠则return true 停止程序游戏结束if (count == 5) {return true;}}}}//不满足上一条件重新设置count的值count = 1;//捺方向判断 x(纵坐标)加1 y(横坐标)加1/x(纵坐标)减1 y(横坐标)减1 查询各4个for (int k = 1; k <= 4; k++) {//判断是否已经出界,且元素不是空值if ((i + k) <= chessboard.length && (j + k) <= chessboard.length && (i - k) > 0 && (j - k) > 0 && (chessboard[i][j] != empty)) {//如果撇方向查询4个发现是相同的棋子则count++if (chessboard[i][j] == chessboard[i + k][j + k] || chessboard[i][j] == chessboard[i - k][j - k]) {count++;//判断如果5子连珠则return true 停止程序游戏结束if (count == 5) {return true;}}}}//不满足上一条件重新设置count的值count = 1;}}//全部不满足条件继续循环return false;}public static void main(String[] args) {Homework2 homework2 = new Homework2();homework2.playChess();}
}

http://www.ppmy.cn/news/846622.html

相关文章

《CSS世界》:一本CSS领域的内功心法修炼手册

来源 | https://chrisdeo.github.io 前言 《CSS世界》这本书可以说是张鑫旭的一本CSS领域的内功心法修炼手册了&#xff0c;阅读这本书&#xff0c;其实是为了印证一些自身在CSS学习上的一些东西&#xff0c;所以&#xff0c;有了这篇读书笔记&#xff0c;记录一些我不是很清晰…

小学校园里计算机文字,中小学计算机教学论文(共2228字).doc

中小学计算机教学论文(共2228字) 中小学计算机教学论文(共2228字) 一、中小学计算机教学现状 计算机作为信息时代发展产物&#xff0c;对人们的生活影响深远&#xff0c;并逐渐成为不可或缺的重要部分。我国计算机教学随着时代的发展&#xff0c;从无到有、从少到多、时至今日&…

工程图字体宋体仿宋_设计干货来了!最热门的宋体字要如何设计搭配?

字体设计搭配是一位优秀设计师必须掌握的学问,宋体字作为汉字最常见的一种字形,如何将宋体运用搭配好呢?一流设计网来为您逐一分析。 虽然说宋体字叫做宋体字,但是如果要追溯宋体字的起源,我们还得从唐朝说起。 唐朝时期,佛教在中国开始盛行开来,唐朝皇帝甚至派出唐僧师…

生僻字怎么用计算机的,最实用生僻字输入方案大全

介绍生僻字输入方法的文章看到过不少,但或过于偏颇,或因条件苛刻使用不便。本文总结最实用的方法,弥补这个不足。 汉字有上万之多,但常用的也就几千个。用电脑写文章偶尔会遇到一些不常用的汉字,看起来面熟但就是不知该如何发音,因而惯用的拼音输入法也就难以派上用场。因…

Python脚本小工具之文件与内容搜索

目录 一、前言 二、代码 三、结果 一、前言 ​日常工作中&#xff0c;经常需要在指定路径下查找指定类型的文件&#xff0c;或者是指定内容的查找&#xff0c;在window环境中&#xff0c;即可以使用一些工具如notepad或everything&#xff0c;也可以使用python脚本。但在l…

CSDN博客的文字颜色、字体和字号设置

CSDN博客的文字颜色、字体和字号设置 一、文本颜色设置方法一代码效果 方法二代码效果 二、文本字号设置代码效果 三、文本字体设置代码效果 四、综合效果代码效果分享 一、文本颜色设置 方法一 代码 <font color red>1.我是文本 红色red</font> <font colo…

Google DeepMind首席执行官Demis Hassabis访谈录

人工智能伴随着挑战和问题&#xff0c;尤其是有一个巨大的组织结构图移动和一系列高风险的决定要做。我很高兴你在这里。 让我们从Google DeepMind本身开始。Google DeepMind是谷歌的一个新部分&#xff0c;由谷歌的两个现有部分组成。有谷歌大脑&#xff0c;这是我们熟悉的人…

lnk306dn引脚功能_LNK306DN LED卤素灯驱动器开关电源

应用功能&#xff1a; 图1所示为使用LNK562DN设计的通用输入、0.98 W输出反激式 电源。电源输出为7 V、0.14 A (1W)&#xff0c;具有宽松的恒压/恒流(CV/CC) 特性(见图2)。此电源用一个630 V额定电压的低值金属膜电容 替代了两个串联的电解电容。此设计非常适用于单相电表或必须…