小言_互联网的博客

Java进阶篇~动力节点(该文章是个人在B站上看动力节点视频学习所做笔记)

293人阅读  评论(0)

面向对象

toString重写

代码演示:
public class Test01
{
	public static void main(String[] arg)
	{
		MyTime my = new MyTime(1000,2,3);
		//未改写toString方法之前输出结果为:MyTime@54bedef2
		//第一种:
		//System.out.println(my.toString());

		//第二种:默认会调用toString方法
		System.out.println(my);
	}
}

class MyTime
{
	int year;
	int month;
	int day;
	//无参构造
	public MyTime(){
	
	}
	//有参构造
	public MyTime(int year, int month, int day)
	{
		this.year = year;
		this.month = month;
		this.day = day;
	}
	//重写toString方法
	public String toString()
	{
		return this.year + "年" +this.month + "月" + this.day + "日";
	}
}

equals重写

代码演示:
public class Test05
{
	public static void main(String[] arg)
	{
		Address addr1 =new Address("北京","朝阳区");
		Address addr2 =new Address("北京","朝阳区");
		Address addr3 =new Address("湖北","武汉市");
		User use1 = new User("李某",addr1);
		User use2 = new User("李某",addr2);
		User use3 = new User("李某",addr3);
		System.out.println(use1.equals(use2));
		System.out.println(use1.equals(use3));
	}
}
class User
{
	String name;
	Address add;

	//无参构造
	public User()
	{
	}
	//有参构造
	public User(String name, Address add)
	{
		this.name = name;
		this.add = add;
	}
	//重写equals方法
	public boolean equals(Object obj)
	{
		//如果obj为空直接返回false
		//如果obj不是一个User,没必要比较了,直接返回false
		if(obj == null || !(obj instanceof User))
		{
			return false;
		}
		//如果this 和obj保存的内存地址相同,没必要比较了,直接返回true。
		//内存地址相同的时候指向的堆内存的对象肯定是同一个。
		if(this == obj)
		{
			return true;
		}
		//将obj进行向下强转
		User u = (User)obj;
		//String引用类型比较,用equals方法
		//相等返回true;不相等返回false
		if (this.name.equals(u.name) && this.add.equals(u.add))
		{
			return true;
		}
		return false;		
	}
		
}

class Address
{
	String city;
	String street;
	//无参构造
	public Address()
	{
	}
	//有参构造
	public Address(String city, String street)
	{
		this.city = city;
		this.street = street;
	}
	//重写equals方法
	public boolean equals(Object obj)
	{
		//如果obj为空直接返回false
		//如果obj不是一个Address,没必要比较了,直接返回false
		if(obj == null || !(obj instanceof Address))
		{
			return false;
		}
		//如果this 和obj保存的内存地址相同,没必要比较了,直接返回true。
		//内存地址相同的时候指向的堆内存的对象肯定是同一个。
		if(this == obj)
		{
			return true;
		}
		//将obj向下强转。
		Address add = (Address)obj;
		//String引用类型比较,用equals方法
		//相等返回true;不相等返回false
		if(this.city.equals(add.city) && this.street.equals(add.street))
		{
			return true;
		}
		return false;
	}
}

final(关键词)

final可以修饰变量以及方法,还有类等。

  1. final修饰的局部变量只能赋值一次。
  2. final修饰的实例变量必须手动赋值初始化。(该实例变量值不会随着对象的变化而变化。所以建议添加static修饰,节约内存空间)。
  3. static final联合修饰的变量称为"常量"。常量名建议全部大写,每个单词之间采用下划线衔接。
  4. final修饰的方法无法被覆盖,重写。
  5. final修饰的类无法继承
  6. final修饰的引用一旦指向某个对象,则不能再重新指向其它对象,但该引用指向的对象内部的数据是可以修改的。(在该方法执行过程中,该引用指向对象之后,该对象不会被垃圾回收器回收。直到当前方法结束,才会释放空间)。
注意:常量和静态变量都是存储在方法区,并且都是在类加载时初始化。

常量一般都是公开的(public)。

代码演示:
public class FinalTest01
{
	public static void main(String[] arg)
	{
		//final修饰变量,只能赋值一次:
		final int i;
		//final修饰引用:
		final A aa = new A();
		//final修饰引用指向的对象内部数据可以被赋值修改的。
		aa = 10;
		//final修饰的引用无法重新指向其他对象。
		aa = new B();//错误!
	}
}
//final修饰类名,无法继承:
final class A
{
	//final修饰方法名无法被覆盖和重写。
	 public final void a()
	{
	
	}
}
final class B
{
	//以后代码不会这么编写20~36行。
	//final修饰实例变量,必须手动赋值。
	//final int bb;//错误,编译器报错
	final int bb = 10;//正确。
	//实例变量在构造方法执行时赋值。
	final int bbb;
	public B()
	{
		this.bbb = 20;
	}

	//实例变量既然使用了final修饰,说明该实例变量值不会随着对象的变化而变化
	//该实例变量前面应该添加:static关键字,变为静态,存储在方法区。
	//static final联合修饰的变量称为"常量"。常量名建议全部大写,每个单词之间采用下划线衔接。
	//常量一般是公开的(public)
	public static final bb_2 = 10;
}

抽象类和接口的区别

抽象类(abstract)

  1. 抽象类简介:
    类和类之间具有共同特征,将这些共同特征提取出来,形成的就是抽象类。
  2. 抽象类属于引用数据类型
  3. 抽象类定义:
    语法:
    [修饰符列表] abstract class 类名
    {
    类体
    }
  4. 抽象类无法实例化,无法创建对象。所以抽象类是用来被子类继承的
    抽象类是类与类之间有共同特征,将这些具有共同特征的类再进一步抽象形成了抽象类。由于类本身不存在的,所以抽象类无法创建对象。
  5. final 和 abstract不能同时出现!!
  6. 抽象类的子类可以抽象化
  7. 抽象类虽然无法实例化,但抽象类有构造方法,它是供子类使用的

抽象方法

抽象方法表示没有实现的方法,没有方法体的方法。
抽象方法的特点是:

  1. 没有方法体,以分号结尾。
  2. 前面修饰符列表中有abstract关键字。
  3. 抽象类中不一定需要抽象方法,但抽象方法必须出现在抽象类中。
注意:一个非抽象类继承抽象类,必须将抽象类中的抽象方法重写/覆盖。
代码演示:
public class AbstractTest02
{
	public static void main(String[] arg)
	{
		//多态:父类型引用指向子类型对象
		Animal a = new Bird();//向上转型(自动类型转换)
		//这是面向抽象编程。
		//调用a.xxx;a的类型是Animal,Animal是抽象的。
		//面向抽象编程,不要面向具体编程,降低程序耦合度,提高程序的扩展力。
		//这种编译思想符合OCP原则。
		//编译父类,运行子类!!!!!
		a.move();//这里运行的是Bird子类中的move方法

		//多态:父类型指向子类型对象
		Animal c = new Cat();//向上转型(自动类型转换)
		//编译父类,运行子类
		c.move();//这里运行的是Cat子类中的move方法	
	}
}
//动物类(抽象类)
abstract class Animal
{
	//抽象方法
	public abstract void move();
}
class Bird extends Animal
{
	//抽象方法必须出现在抽象类中
	//报错:AbstractTest02.java:15: 错误: Bird不是抽象的, 并且未覆盖Animal中的抽象方法main()
	//由于继承了抽象类Animal中的抽象方法,需要进行重写,覆盖,否则编译器报错.
	public void move(){//更正后的正确代码
		System.out.println("鸟儿会飞翔");
	}
}

//抽象方法必须出现在抽象类中
//如果抽象类继承抽象类,则不需要重写抽象方法
//但是抽象类中无法实例化对象!!!
/*
abstract class Bird extends Animal
{
}
*/
class Cat extends Animal
{
	public void move()
	{
		System.out.println("猫儿在走猫步");
	}
}
面试题:java语言中凡是没有方法体的方法都是抽象方法。
	错误。
	Object类中就有很多方法都没有方法体,都是以“;”结尾,但他们都不是抽象方法。
	因为底层调用了c++写的动态链接库程序。
	修饰符列表中有一个native。表示调用JVM本地程序。

接口(interface):

基础语法
  1. 接口也是一种“引用数据类型”。编译之后也是一个class字节码文件。
  2. 接口是特殊的抽象类(完全抽象),接口通常提取的是行为动作。-----抽象类是半抽象。
  3. 接口定义,语法是:
    [修饰符列表] interface 接口名()
  4. 接口支持多继承,一个接口可以继承多个接口。
  5. 接口和接口之间在进行强制转换时,没有继承关系也可以强转
  6. 接口中只有常量和抽象方法
  7. 接口中所有元素都是public修饰的。(都是公开的)
  8. 接口中的抽象方法定义时: public abstract修饰符可以省略。
  9. 接口中的方法不能有方法体
  10. 接口中的常量public static final 可以省略
  11. 当继承extends与实现implements同时存在时:extends 在前,implements 在后。
  12. 当一个非抽象类继承抽象类必须将抽象类中的所有方法全部实现(覆盖,重写)。用implements实现,不是extends。
  13. 一个类可以实现多个接口
  14. 使用接口编写代码时可以使用多态(父类型引用指向子类型对象)。
  15. 接口和接口之间在进行强制转换时,无论是向上还是向下转型,没有继承关系也可以强转。(见代码-----第二段)
代码演示:
第一段


public class Test02
{
	public static void main(String[] arg)
	{
		//错误!!! MyMath是抽象的,无法实例化。
		//new MyMath();
		//多态:父类型的引用指向子类型的对象
		MyMath mm = new MyMathImple();
		int result1 = mm.sum01(10, 20);
		int result2 = mm.sum02(10, 20);
		System.out.println(result1);
		System.out.println(result2);
	}
}


//特殊的抽象类,完全抽象,叫做接口
interface MyMath
{
	//常量
	//public static final double PI = 3.14159265;
	//public static final 可以省略
	//所以接口中随便写一个变量都是常量
	//因为在interface中默认添加public static final。
	double PI = 3.14;
	//抽象方法
	//public abstract int sum(int a, int b);
	//接口中既然都是抽象方法,那么public abstract可以省略。
	//接口抽象方法不能带有主体。
	int sum01(int a, int b);
	int sum02(int a, int b);

}
//编写一个类(这个类是一个“非抽象”的类)
/*
//错误
class MyMathImpl extends MyMath
{
}
*/

//修改方案一:
/* 抽象类继承接口类。
abstract class MyMathImple implements MyMath
{
}
*/

//修改方案二:
//重写接口(完全抽象)内的方法。
 class MyMathImple implements MyMath
{
	//这里需要(实现)重写/覆盖。
	//去掉public会报错,因为访问权限只能更高,不能更低。
	public int sum01(int a, int b)
	{
		return a + b;
	}
	public int sum02(int a, int b)
	{
		return a - b;
	}
}

第二段
public class Test03
{
	public static void main(String[] arg)
	{
		//多态:父类型A引用指向子类型D的对象
		A a = new D();
		B b = new D();
		//调用其它接口中的方法,需要转型(接口转型)
		//方法一:
		B b2 = (B)a;
		b2.m2();

		//方法二:(直接向下转型,)
		D d = (D)a;
		d.m2();
		d.m1();
		
		//
		A aa = new E();
		aa.m1();
	}
}

interface A
{
	void m1();
}
interface B
{
	void m2();
}


//实现多个接口,其实就类似于多继承,D继承A,B,C
class D implements A, B
{
	//实现(重写/覆盖)A接口中的m1方法。
	public void m1(){
		System.out.println("m1..");
	}
	//实现(重写/覆盖)A接口中的m2方法。
	public void m2(){
		System.out.println("m2..");
	}

}

class C
{

}
//当继承extends与实现implements同时存在时:extends 在前,implements 在后。
class E extends C implements A
{
	public void m1()
	{
		System.out.println("m1..");
	}
}

ClassCastException异常见链接:ClassCastException异常
接口在开发中的作用:
  1. 接口的作用类似于多态在开发中的作用。
    多态:面向抽象编程,不要面向具体变成,降低程序的耦合度,提高程序的扩展力。
  2. 接口:面向抽象(接口)编程,降低程序耦合度。接口使用离不开多态机制(接口+多态)
  3. 接口是将调用者和实现者解耦合。
    调用者面向接口调用
    实现者面向接口编写实现。

类型与类型之间的关系: is a, has a, like a

is a(继承):
Cat is a Animal(猫是一个动物)
凡是能满足is a的表示“继承关系”
A extends B
has a(关联):
I has a Pen(我有一只笔)
凡是能够满足 has a关系的表示“关联关系”
关联关系通常以“属性”的形式存在。
A{
	B b;
}
like a(实现):
Cooker like a FoodMenu(厨师像一个菜单一样 ----   菜单有的,厨师都能做)
司机像导航
凡是能够满足like a关系的表示“实现关系”
实现关系通常是:类实现接口。
A implements B

抽象类与接口的语法区别:

  1. 抽象类是半抽象的,接口是完全抽象的。
  2. 抽象类有构造方法,接口没有构造方法。
  3. 类和类之间只能单继承,接口和接口之间支持多继承
  4. 一个抽象类只能继承一个类(单继承),一个类可以同时实现多个接口。
  5. 接口中只允许出现常量和抽象方法-----接口一般都是对“行为”的抽象。

package 和 import

package :(Java中的包机制)

作用:为了方便程序的管理,不同功能的类分别存放在不同的包下。
使用:

package是一个关键字,后面+包名
代码:package com.bjpowernode.javase.chapter17;
包名:
一般采用公司域名倒序的方式(公司域名具有全球唯一性)。
	命名规范:
			公司域名倒序 + 项目名 + 模块名 + 功能名

注意: package语句只允许出现在Java源代码中的第一行。
编译: javac -d . HalloWorld.java

javac	负责编译的命令。
-d 	 	带包编译
.  		代表编译之后生成的东西放到当前目录下(点代表当前目录)
HalloWorld.java		被编译的Java文件名。

运行:

Java 完整类名
 java com.bjpowernode.javase.chapter17.HalloWorld
 com.bjpowernode.javase.chapter17.HalloWorld 是完整类名
 HalloWorld 是简类名

import 将需要的类导入。

使用:

Java.lang不需要,同包下不需要。其它都需要。
A类中使用B类。
A类和B类不再同一个包下,需要使用import。
如果A类和B类都在同一个包下,不需要import。
imprt语句只能出现在class上面,backage下面。
注意:java.lang.* ,这个包下的不需要导入。

访问控制权限

访问控制权限的范围:

修饰:
属性(4个都能用)
方法(4个都能用)
类(public 和默认都能用,其它不行)
接口(public 和默认能用,其它不行)

匿名内部类:

内部类:在类的内部又定义了一个新的类,被称为内部类。
内部类分类:

静态内部类:类似于静态变量
实例内部类:类似于实例变量
局部内部类:类似于局部变量
  1. 尽量不要使用内部类,可读性差,无法二次复用。
  2. 匿名内部类属于局部内部类的一种,因为这种类没有名字而得名:匿名内部类。
代码演示:
class Test01{

	// 静态变量
	static String country;
	// 该类在类的内部,所以称为内部类
	// 由于前面有static,所以称为“静态内部类”
	static class Inner1{
	}
	
	// 实例变量
	int age;
	// 该类在类的内部,所以称为内部类
	// 没有static叫做实例内部类。
	class Inner2{
	}

	// 方法
	public void doSome(){
		// 局部变量
		int i = 100;
		// 该类在类的内部,所以称为内部类
		// 局部内部类。
		class Inner3{
		}
	}

	public void doOther(){
		// doSome()方法中的局部内部类Inner3,在doOther()中不能用。
	}

	// main方法,入口
	public static void main(String[] args){
		// 调用MyMath中的mySum方法。
		MyMath mm = new MyMath();
		/*
		Compute c = new ComputeImpl();
		mm.mySum(c, 100, 200);
		*/
		
		//合并(这样写代码,表示这个类名是有的。类名是:ComputeImpl)
		//mm.mySum(new ComputeImpl(), 100, 200);
	
		// 使用匿名内部类,表示这个ComputeImpl这个类没名字了。
		// 这里表面看上去好像是接口可以直接new了,实际上并不是接口可以new了。
		// 后面的{} 代表了对接口的实现。
		// 不建议使用匿名内部类,为什么?
		// 因为一个类没有名字,没有办法重复使用。另外代码太乱,可读性太差。
		mm.mySum(new Compute(){
			public int sum(int a, int b){
				return a + b;
			}
		}, 200, 300);



	}

}

// 负责计算的接口
interface Compute{ 
	
	// 抽象方法
	int sum(int a, int b);
}

// 你自动会在这里编写一个Compute接口的实现类
/*
class ComputeImpl implements Compute{

	// 对方法的实现
	public int sum(int a, int b){
		return a + b;
	}
}
*/

// 数学类
class MyMath{
	// 数学求和方法
	public void mySum(Compute c, int x, int y){
		int retValue = c.sum(x, y);
		System.out.println(x + "+" + y + "=" + retValue);
	}	
}

数组

  1. Java语言中的数组是一种引用数据类型。不属于基本数据类型,数组的父类是Object.。
  2. 数组是一个容器,可以同时容纳多个元素(数组是一个数据的集合。)字面意思:“一组数据”。
  3. 数组当中可以存储基本数据类型的数据,也可以储存引用数据类型的数据。
  4. 数组因为是引用类型,所以数组对象是堆内存当中。(数组是存储在堆当中的)
  5. 数组当中如果存储的是“Java对象”的话,实际上存储的是对象的“引用(内存地址)”,数组中不能直接存储Java对象。
  6. 数组一旦创建,在Java中规定,长度不可变
  7. 数组分类:一维数组,二位数组,三维数组,多维数组…(一维数组较多,二维数组偶尔使用)
  8. 所有的数组对象都有lenth属性(Java自带),用来获取数组中元素的个数。
  9. Java中的数组要求数组中元素的类型统一。比如int类型数组只能存储int类型,person类型数组只能存储person类型。
  10. 数组在内存存储时,数组中的元素内存地址时连续的(存储的每一个元素都是有规则的),数组实际上是一种数据结构。
  11. 数组中每个元素都是有下标的,下标从0开始,以1递增,最后一个元素的下标是(length - 1 ), 数组中的首元素内存地址作为数组的内存地址。
  12. 数组的优点:查询/查找某个下标上的元素时效率极高。可以说是查询效率最高的一个数据结构。
  13. 数组缺点:
    1. 在数组上随机删除或者增加元素时,效率较低,因为随机增删元素会涉及到后面元素统一向前或向后位移的操作。
    2. 数组不能存储大数据量:因为很难在内存空间上找到一块特别大的连续的内存空间。
面试题:为什么检索效率高?
1. 每个元素的内存地址在空间存储上是连续的。
2. 每个元素的类型相同,即所占空间大小相同。
3. 知道第一个元素的内存地址,元素所占空间的大小,及其下标,可以通过一个数学表达式就可以计算出某个下标上元		素的内存地址,直接通过内存地址定位元素,所以检索效率最高。

一维数组:

语法格式:
int [] array1;
Object[] array2;

初始化一维数组:包括静态初始化和动态初始化。
静态初始化:

int[] array ={100,200,500};

动态初始化:

//这里的5表示数组的个数
//初始化一个5个长度的int类型数组,每个元素默认值为0
int[] array = new int[5];
//初始化6个长度的String类型数组,每个元素默认值为null
String[] array = new String[6];
当创建数组时,确定数组中存储哪些具体的元素时,采用静态初始化方式。
当创建数组时,不确定将来数组中存储哪些数据,你可以采用动态初始化方式,预先分配内存空间。
数组扩容:

在java开发中,数组长度一旦确定则不可变,数组满了需要扩容。
扩容:(数组扩容效率低。因为涉及到拷贝的问题。)

先新建一个大容量的数组,然后将小容量数组中的数据一个一个拷贝到大数组中。

建议:

在创建数组对象的时候预估多长合适,最好预估准确,这样可以减少数组的扩容次数,提高效率。
代码演示:
一维数组:(用一维数组模拟入栈,出栈)
package com.bjpowernode.javase.array;

public class HomeWork01_2 {
    public static void main(String[] args) {
        //MyStack stack = new MyStack(10,-1);//这里是给有参构造传递参数
        MyStack stack = new MyStack();
        stack.push(new Object());
        stack.push(new Object());
        stack.push(new Object());
        stack.push(new Object());
        stack.push(new Object());
        stack.push(new Object());
        stack.pop();
        stack.pop();
        stack.pop();
        stack.pop();
        stack.pop();

    }
}
class MyStack{
    //也可以在后面无参构造中默认初始化容量:this.elements = new Object[10];
    //private Object[] elements = new Object[10];
    private Object[] elements;
    private int index;
    //无参构造
    public MyStack()
    {
        //建议直接在无参构造中给一维数组长度,数据类型等进行初始化,
        //一维数组初始化
        //默认初始化容量为4
        this.elements = new Object[4];
        //默认初始化index为-1,-1表示指向栈顶元素。
        this.index = -1;
    }
    //有参构造
    /*
    public MyStack(Object length, int index) {
        //这里是将main方法中的参数传进来,给一维数组长度进行赋值,有些许多此一举。
        this.elements = new Object[Integer.parseInt(String.valueOf(length))];
        this.index = index;
    }*/

    //elements 的Setter and Getter方法
    public Object[] getElements() {
        return elements;
    }

    public void setElements(Object[] elements) {
        this.elements = elements;
    }
    //index的setter and getter
    public int getIndex() {
        return index;
    }

    public void setIndex(int index) {
        this.index = index;
    }

    public void push(Object obj){
        if (index >= elements.length -1)
        {
            System.out.println("压栈失败,栈已满");
            return;
        }
        index++;
        elements[index] = obj;
        //所有System.out.println()方法执行时,如果输出引用,自动调用toString()方法。
        System.out.println("压栈"+obj+"元素成功,栈帧指向"+index);
    }
    public void pop()
    {
        if (index < 0)
        {
            System.out.println("弹栈失败");
            return;
        }
        System.out.println("弹栈"+elements[index]+"元素成功,栈帧指向"+(index--));
    }
}
自创版:(用一维数组模拟栈,出栈,入栈)
package com.bjpowernode.javase.array;
import java.util.Scanner;
public class HomeWork01 {
    public static void main(String[] args) {
        Mystack m = new Mystack(4);
        //Object[] obj= new Object[4];
        m.push();
        System.out.println("=======");
        m.pop();
    }
}
class Mystack{
    Object[] elements;
    //无参构造
    public Mystack(){

    }
    //有参构造
    public Mystack(Object length)
    {

        this.elements = new Object[Integer.parseInt(String.valueOf(length))];
    }
    //压栈
    public void push()
    {

       for (int i = 1; i > 0 ; i++) {
            System.out.print("请输入第"+ i +"个元素数据:");
            Scanner s = new Scanner(System.in);
            elements[i-1] = s.next();
          // System.out.println("栈帧为:"+elements[i - 1]);
            if (i < elements.length) {
                System.out.println("栈内存还剩" + (elements.length - i));
            }else {
                System.out.println("栈内存以用完,无法压栈");
                break;
            }
        }
        System.out.print("输入所有数据为:");
        for (int i = 0; i < elements.length ; i++) {
            System.out.print(elements[i] + "\t");
        }
        System.out.println("");
    }
    //出栈
    public void pop()
    {
        for (int i = elements.length - 1; i < elements.length ; i--) {
            elements[i] = null;
            if(i > 0) {
                System.out.println("出栈数据为:");
                for (int j = 0; j < elements.length; j++) {
                    System.out.print(elements[j] + "\t");
                }
                System.out.println("");
                //System.out.println("出栈所有数据为:"+elements[i]);
            }else {
                for (int j = 0; j < elements.length; j++) {
                    System.out.print(elements[j] + "\t");
                }
                System.out.println("栈已空,弹栈失败");
                break;
            }
        }
    }
}
数组扩容:
package com.bjpowernode.javase.array;

public class ArrayTest05 {
    public static void main(String[] args) {
        //拷贝:System.arraycopy(5个参数)
        //拷贝源:(从这个数组内拷贝)
        int[] src = {1,2,312,435,546};//静态数组
        //拷贝目标(拷贝到这个数组上)
        int[] dest = new int[10];//动态初始化一个长度为10的数组,默认值为0

        //调用JDK System类中的arraycopy方法完成拷贝.
        /*拷贝数组中的部分数据
        src 表示被拷贝的数组源,1 表示从被拷贝的数组源源的第1个起始位置开始
        dest 表示目标源(接收原数组数据的数组), 2 表示从第2个位置开始进行粘贴
        3 表示拷贝粘贴数组的长度。
        System.arraycopy(src, 1, dest, 2, 3);

        //遍历目标数组
        for (int i = 0; i <dest.length ; i++) {
            System.out.println(dest[i]);
        }
        */
        //拷贝数组中的所有元素
        System.arraycopy(src, 0, dest, 0, src.length);
        for (int i = 0; i <dest.length ; i++) {
            System.out.println(dest[i]);
        }
        System.out.println("==================");
        //引用数据类型
        // 拷贝源:
        String[] str1 = {"aj","asd","da"};
        //粘贴到:
        String[] str2 = new String[5];
        //拷贝数组中的所有元素。
        System.arraycopy(str1,0,str2, 0,str1.length);
        for (int i = 0; i <str2.length ; i++) {
            System.out.println(str2[i]);
        }
        
        
        System.out.println("======================");
        //最终输出结果为:地址!!!
        //拷贝源:
        Object[] obj1 = {new Object(),new Object(),new Object()};
        //粘贴:
        Object[] obj2 = new Object[5];
        //拷贝数组中所有元素
        System.arraycopy(obj1, 0, obj2, 0,obj1.length);
        //遍历
        for (int i = 0; i <obj2.length ; i++) {
            System.out.println(obj2[i]);
        }
    }
}

二维数组及多维数组

二维数组是一个特殊的一维数组,特殊在这个二维数组当中的每个元素都是一个一维数组。
N维数组是一个特殊的(N-1)数组,特殊在这个(N-1)维数组中的每一个元素都是一个(N-2)维数组。

语法格式:
//二维数组:
int[][] a = {{100,23,452},{213,36,123},{87,324,45}};
代码演示:(运用到二维数组的酒店管理系统)

自己琢磨,无说明。

package com.bjpowernode.javase.array;
import java.util.Scanner;
import javax.swing.*;

public class HotelMgt {
    public static void main(String[] args) {
        Hotel hotel = new Hotel();
        hotel.print();
        System.out.println("请输入功能编号:【1】查看\t【2】订房\t【3】退房\t【4】退出系统");
        while (true) {
            Scanner s = new Scanner(System.in);
            System.out.print("请输入功能编号:");
            int i = s.nextInt();
            switch (i) {
                case 1:
                    hotel.print();
                    break;
                case 2:
                    System.out.print("请输入订房房间号:");
                    Scanner roomNo = new Scanner(System.in);
                    hotel.order(roomNo.nextInt());
                    break;
                case 3:
                    System.out.println("请输入退房房间号:");
                    Scanner roomNo2 = new Scanner(System.in);
                    hotel.exit(roomNo2.nextInt());
                    break;
                case 4:
                    System.out.println("欢迎下次使用,再见!");
                    return;
                default:
                    System.out.println("输入功能编号有误,请重新输入:");
            }
        }
    }
}
class Room{
    private int no;
    private String type;
    private boolean status;

    public Room(){

    }

    public Room(int no, String type, boolean status) {
        this.no = no;
        this.type = type;
        this.status = status;
    }

    public int getNo() {
        return no;
    }

    public void setNo(int no) {
        this.no = no;
    }

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }

    public boolean isStatus() {
        return status;
    }

    public void setStatus(boolean status) {
        this.status = status;
    }
    public String toString() {
        return no +type+(status ? "空闲" : "占用");
    }
    public boolean equals(Object obj){
        if (obj == null || !(obj instanceof Room)){
            return false;
        }
        if (this == obj){
            return true;
        }
        Room room = (Room)obj;
        return (this.getNo() == room.getNo());
    }
}

class Hotel{
    private Room[][] rooms;
    public  Hotel(){
        rooms = new Room[3][10];
        for (int i = 0; i <rooms.length ; i++) {
            for (int j = 0; j <rooms[i].length ; j++) {
                if (i == 0){
                    rooms[i][j] = new Room((i+1)*1000+j+1,"单人间",true);
                }else if (i == 1){
                    rooms[i][j] = new Room((i+1)*1000+j+1,"标准间",true);
                }else if(i == 2){
                    rooms[i][j] = new Room((i+1)*1000+j+1,"豪华间",true);
                }
            }
        }
    }
    public void print(){
        for (int i = 0; i <rooms.length ; i++) {
            for (int j = 0; j <rooms[i].length ; j++) {
                System.out.print(rooms[i][j]+"\t");
            }
            System.out.println("");
        }
    }
    public void exit(int roomNo){
        Room room = rooms[roomNo/1000-1][roomNo%1000-1];
        room.setStatus(true);
        System.out.println(roomNo+"已退房");
    }
    public void order(int roomNo){
        Room room = rooms[roomNo/1000-1][roomNo%1000-1];
        room.setStatus(false);
        System.out.println(roomNo+"已入住");
    }
}

数组元素查找:

二分法查找:(先排序)
  1. 二分法查找建立在排序的基础上。
  2. 二分法效率高于“傻瓜式查找:一个一个找”。
代码演示:
import java.util.Scanner;
public class ArraySearch {
    public static void main(String[] args) {
        Scanner s = new Scanner(System.in);
        System.out.print("请输入你要找的元素:");
        int ss = s.nextInt();
        int[] arr = {2,3,1,8,4,6,5,1};
        //方法一:(傻瓜式)线形查找
        Math m = new Math();
        int i = m.math(ss,arr);
        System.out.println((i == -1) ? "未找到该数据,请重新输入!" : "下标为:"+i);
        //方法二:二分法查找:先排序后查找
        Math02 m2 = new Math02();
        int i2 = m2.math02(ss,arr);
        System.out.println((i2 == -1) ? "未找到该数据,请重新输入!" : "下标为:"+i2);
    }
}
//线形查找

class Math{
    public int math(int ss,int[] arr){
        for (int i = 0; i <arr.length ; i++) {
            if (ss == arr[i]){
                return i;
            }
        }
        return -1;
    }
}
//二分法查找
class Math02{
    public int math02(int ss,int[] arr){
        for (int i = 0; i <arr.length - 1 ; i++) {
            int min = i;
            for (int j = i+1; j <arr.length ; j++) {
                // count2++;
                if (arr[j] < arr[min]){

                    min = j;//最小值元素的下标是j。
                }
            }
            //当i和min相等时,表示最初猜想是对的。
            //当i和min不相等时,表示最初猜测时错的,有比这个元素更小的元素。
            //需要拿这个更小的元素和最左边的元素交换位置。
            if(min != i)
            {
                int temp;
                temp = arr[i];
                arr[i] = arr[min];
                arr[min] = temp;
            }
        }
        //数组遍历
        /*
        for (int i = 0; i <arr.length ; i++) {
            System.out.println(arr[i]);
        }

         */

        //二分法查找
        //表示开始的下标
        int begin = 0;
        //表示结束的下标
        int end = arr.length-1;
        //开始元素的下标只要在结束元素下标的左边,就有机会继续循环。
        while (begin <= end) {
            //中间元素的下标
            int mid = (begin + end) / 2;
            if (arr[mid] == ss) {
                return mid;
            } else if (arr[mid] < ss) {
                //目标在“中间”的右边
                //开始元素下标需要发生变化(开始元素的下标需要重新赋值)
                begin = mid + 1;//一直增加
            } else {
                //目标在“中间”的左边
                //修改结束元素的“下标”
                end = mid - 1;//一直减
            }
        }
        return -1;
    }
}

常用算法:

冒泡排序:(BubbleSort)

首先从数组最左边数据开始,取第0号位置(左边)的数据和第1号位置(右边)的数据,如果左边的数据大于右边的数据,则进行交换,反之则不交换。
然后取第一个位置的数据和第二个位置的数据,进行比较,如果左边大于右边,则进行交换,反之则不交换。

代码演示:
public class BubbleSort {
    public static void main(String[] args) {
        //这是int类型的数组对象
        int arr[] = {2123,323,2344,535,61,37};
        int count = 0;
        int counts = 0;
        //6条数据,循环5次,每次循环将第一个数与后面的数依次比较,并取出最大值放在最右边,
        // 下次循环排除最大值。将剩下的数据按照第一次循环一样依次比较。

        for (int i = arr.length - 1; i >0 ; i--) {
            //内部循环就是将数字进行比较,并交换位置,将最大值放在右边
            counts ++;
            for (int j = 0; j <i ; j++) {
                count++;
                if (arr[j] > arr[i])
                {
                    int temp;
                    temp = arr[j];
                    arr[j] = arr[i];
                    arr[i] = temp;
                }
            }
        }
        System.out.println("比较次数:" + count + "外部循环次数:"+ counts);
        for (int i = arr.length - 1; i >0 ; i--) {
            System.out.print(arr[i] + "\t>\t");
        }
    }
}

选择排序:(SelectSort)

选择排序比冒泡排序的效率高。高在交换位置的次数上。选择排序交换位置是有意义的。
循环一次,然后找出参加比较的这堆数据中最小的,拿着这个最小的值和最前面的数据交换位置。

代码演示:
public class SelectSort {
    public static void main(String[] args) {
        int[] arr = {251,23,435,565,123};
       // int count2 = 0;
      //  int count = 0;
        //5个数据只需要循环四次,所以是arr.length-1
        //i是一个参与比较的这堆数据中的起点下标。
        for (int i = 0; i <arr.length - 1 ; i++) {
            int min = i;
            for (int j = i+1; j <arr.length ; j++) {
              // count2++;
                if (arr[j] < arr[min]){

                    min = j;//最小值元素的下标是j。
                }
            }
            //当i和min相等时,表示最初猜想是对的。
            //当i和min不相等时,表示最初猜测时错的,有比这个元素更小的元素。
            //需要拿这个更小的元素和最左边的元素交换位置。
            if(min != i)
            {
                int temp;
                temp = arr[i];
                arr[i] = arr[min];
                arr[min] = temp;
              //  count++;
            }
        }
       // System.out.println("交换位置次数"+count);
       // System.out.println("比较次数" + count2);
        //数组遍历
        for (int i = 0; i <arr.length ; i++) {
            System.out.println(arr[i]);
        }
    }
}

数组工具类Arrays

所有方法都是静态的,直接用类名调用
	主要使用的是两个方法:
		二分法查找,排序
	以后要看文档,不要死记硬背。
代码演示:
import java.util.Arrays;

public class ArraysTest01 {
    public static void main(String[] args) {
        int[] arr = {3,5,2,1,5,7,9,6,0};
        //调用Object中的Arrays.sort方法排序:
        Arrays.sort(arr);

        //二分法查找:
        int index = Arrays.binarySearch(arr,5);
        System.out.println(index == -1 ? "不存在" : "该元素下标" + index);
    }
}

String

  1. String表示字符串类型,属于引用数据类型,不属于基本数据类型。
  2. 在Java中使用双引号括起来的都是String类型。例如:“abc”。
  3. Java中规定,双引号括起来的都是不可变的。
  4. 在JDK当中双引号括起来的字符串都是存储在方法区内

面试题:

public class StringTest02 {
    public static void main(String[] args) {
        //这一共new了几个对象?
        //5个:3个堆内存中的String对象,还有2个方法区常量池中的"hello"和"hahaha".
        String a = new String("hello");
        String b = new String("hello");
        String c = new String("hahaha");
    }
}

关于String类中的常用方法

代码演示:

import java.util.Arrays;

public class StringTest03 {
    public static void main(String[] args) {
        //charAt表示返回指定索引处的char值,括号内是索引(下标).
        //"中国人"是一个字符串String对象,所以可以"对象.引用"
        char c = "中国人".charAt(1);
        System.out.println(c);

        //compareTo表示按字典顺序比较两个字符串,返回值类型为int,并可以看出谁大谁小
        System.out.println("abc".compareTo("abc"));//0
        int result = "cdf".compareTo("atv");//2
        System.out.println(result);

        //contains:  当且仅当此字符串包含指定的 char 值序列时,返回 true.返回值类型为boolean
        System.out.println("halloWorld".contains("a"));//true

        //endsWith: 判断此字符串是否以指定的后缀结束.返回值类型为:boolean.
        System.out.println("halloworld".endsWith("world"));//true

        //startsWith:判断此字符串是否以某个字符串开始.返回值类型为:boolean.
        System.out.println("halloworld".endsWith("world"));//false

        //equalsIgnoreCase:将此 String 与另一个 String 比较,不考虑大小写.
        System.out.println("HalloWorld".equalsIgnoreCase("halloworld"));//true

        //getBytes() : 使用平台的默认字符集将此 String 编码为 byte 序列,并将结果存储到一个新的 byte 数组中。
        byte[] b = "dskfa".getBytes();
        //遍历数组:
        //方法一:foreach:
        for(int i : b){
            System.out.print(i + "\t");//100	115	107	102	97
        }
        //方法二:利用jdk自带方法:java.util.Arrays.toString
        System.out.println(Arrays.toString(b));//[100, 115, 107, 102, 97]

        //int indexOf(String str):返回指定子字符串在此字符串中第一次出现处的索引.
        System.out.println("dahagdsasdhgasdgahsdgyad".indexOf("a"));//1

        //int lastIndexOf(String str):返回某个字符串在当前字符串中最后一次出现的索引(下标)
        System.out.println("asdasdasdassdfsdczxcasdadQFRQ".lastIndexOf("a"));//23

        //isEmpty():判断字符串是否为空字符串,如果为空则返回true.
        String s = "";
        System.out.println(s.isEmpty());//true

        //int length()
        //面试题:判断数组长度和判断字符串长度不一样。
        //判断数组长度是length属性,判断字符串长度是length()方法
        System.out.println("sdad".length());//4

        //replace(CharSequence target, CharSequence replacement)
        //将字符串中与target内容相同的所有字符全部替换成replacement的字符串内容
        //String的父接口是:CharSequence
        String newString = "李李,你好,你好".replace("你好", "Hallo");
        System.out.println(newString);//"李李,hallo,hallo"

        //split(String regex) :将字符串进行以regex内容进行拆分并以数组形式存储
        String[] newString02 = "1,2,3,456,123,586".split(",");
        for (int i = 0; i <newString02.length ; i++) {
            System.out.print(newString02[i] + "\t");//1	2	3	456	123	586
        }

        //substring(int beginIndex) :截取字符串,参数是起始下标.
        System.out.println("www.baidu.com".substring(5));//aidu.com

       // String substring(int beginIndex, int endIndex):
        //beginIndex:包括该位置
        //endIndex :不包括该位置
        System.out.println("www.baidu.com".substring(3,7));//.bai

        //char[] toCharArray() :将此字符串转换为一个新的cahr数组
        char[] chars = "我是中国人".toCharArray();
        for (int i = 0; i <chars.length ; i++) {
            System.out.print(chars[i] + "\t");//我	是	中	国	人
        }

        //toLowerCase() :使用默认语言环境的规则将此 String 中的所有字符都转换为小写。
        System.out.println("ABCDEFG".toLowerCase());//abcdefg
        //toUpperCase():使用默认语言环境的规则将此 String 中的所有字符都转换为大写。
        System.out.println("asdasd".toUpperCase());//ASDASD

        //trim() :去除字符串前后空白
        System.out.println("            Hello       World       ".trim());//Hello       World

        //valueOf:将非字符串转换成"字符串"
        //该方法时String类型中唯一一个静态方法,不需要new对象
        String s1 = String.valueOf(100);//
        String s2 = String.valueOf(true);
        System.out.println(s1);//100
        System.out.println(s2);//true
        //当这个静态valueOf()方法,参数是一个对象时,会自动调用该对象的toString方法。
        //没有重写Customer类中的toString时,输出结果时对象内存地址。
        String s3 = String.valueOf(new Customer());
        //本质上:System.out.println()这个方法在输出任何数据的时候都会先转换成字符串,再输出
        System.out.println(s3);//com.lt.javase.string.Customer@27bc2616
    }
}
class Customer{
    public String toString() {
        return "我是VIP";
    }
}

StringBuffer

语法:

如果以后需要进行大量字符串的拼接操作,建议使用JDK中自带的java.lang.StringBuffer    java.lang.StringBuilder
StringBuffer底层实际上是一个byte[]数组。
往StringBuffer中房字符串,实际上时放到byte[]数组中。
StringBuffer的初始化容量是16.

优化StringBuffer性能(自动扩容效率太低,扩容越少,效率越高):

* 在创建StringBuffer时尽可能顶一个初始化容量
* 最好减少底层数组的扩容次数。预估一下给一个大一些的初始化容量。
代码演示:
/*
* 如果以后需要进行大量字符串的拼接操作,建议使用JDK中自带的
* java.lang.StringBuffer    java.lang.StringBuilder
* 优化String性能:
* 在创建StringBuffer时尽可能顶一个初始化容量
* 最好减少底层数组的扩容次数。预估以下给一个大一些的初始化容量。
* */
public class StringBufferTest01 {
    public static void main(String[] args) {
        //StringBuffer底层实际上是一个byte[]数组。
        //往StringBuffer中房字符串,实际上时放到byte[]数组中。
        //StringBuffer的初始化容量是16.
        StringBuffer stringBuffer = new StringBuffer("abc");
        //拼接字符串,以后拼接字符串统一调用append()方法
        //append是追加的意思。
        stringBuffer.append("a");
        //append方法底层在进行追加的时候,如果byte数组满了,会自动扩容。
        System.out.println(stringBuffer);

        //指定初始化(capacity)容量的StringBuffer对象(字符串缓冲区对象)
        StringBuffer sb = new StringBuffer(100);
        sb.append("hello");
        sb.append(" world");
        System.out.println(sb);
    }
}

StringBuilder与StringBuffer的区别:

  • java.lang.StringBuild
  • StringBuffer和StringBuilder区别:
  • StringBuffer方法中都有synchronized关键字修饰,表示StringBuffer在多线程环境下运行是安全的。
  • StringBuilder方法中没有synchronized关键字修饰,表示StringBuilder在多线程环境下运行是不安全的。
  • StringBuffer是线程安全的,StringBuilder是非线程安全

StringBuilder代码演示:

public class StringBuildTest01 {
    public static void main(String[] args) {
        StringBuilder stringBuilder = new StringBuilder("a");
        stringBuilder.append("b");
        System.out.println(stringBuilder);
    }
}

8种包装类

Java中为8种基本数据类型对应的准备了8种包装类型。8种包装类属于引用数据类型,父类是Object

基本数据类型             	包装类型
---------------------------------------
byte					java.lang.Byte(父类Number)
short					java.lang.Short(父类Number)
int						java.lang.Integer(父类Number)
long					java.lang.Long(父类Number)
float					java.lang.Float(父类Number)
double					java.lang.Double(父类Number)
boolean					java.lang.Boolean(父类Object)
char					java.lang.Charater(父类Object)

Number类:

Number是一个抽象类,无法实例化对象。
Number类中有这样的方法:(这些方法所有的数字包装类的子类都有,这些方法是负责拆箱的)

byte byteValue() 
          以 byte 形式返回指定的数值。 
abstract  double doubleValue() 
          以 double 形式返回指定的数值。 
abstract  float floatValue() 
          以 float 形式返回指定的数值。 
abstract  int intValue() 
          以 int 形式返回指定的数值。 
abstract  long longValue() 
          以 long 形式返回指定的数值。 
 short shortValue() 
          以 short 形式返回指定的数值。 

将基本数据类型转换为引用数据类型叫装箱
将引用数据类型转换为基本数据类型叫拆箱

代码演示:
/*
* Java中为8种基本数据类型对应的准备了8种包装类型。8种包装类属于引用数据类型,父类是Object*/
public class IntegerTest01 {
    public static void main(String[] args) {
        //12这是一个基本数据类型,进行构造方法包装达到了:基本数据类型向引用数据类型的转换。
        //基本数据类型——(转换为)——>引用数据类型(装箱)
        Integer i = new Integer(12);
        //将引用数据类型——(转换为)——>基本数据类型
        float f = i.floatValue();
        System.out.println(f);//12.0
        //将引用数据类型——(转换为)——>基本数据类型(拆箱)
        int retValue = i.intValue();
        System.out.println(retValue);//12
    }
}

面试题:String为什么是不可变的?

我看过源代码。String类中有一个byte[]数组,这个byte[]数组采用了final修饰,因为数组一旦创建后长度不可变,并且被final修饰的引用一旦指向某个对象之后,不可再指向其它对象。所以String不可变。

面试题:StringBuffer/StringBuilder为什么是可变的?

我看过源代码,StringBuffer/StringBuilder内部实际上是一个byte[]数组,这个byte[]数组没有被final修饰,StringBuffer/StringBuilder的初始化容量为16,存满后会进行扩容,底层调用了数组拷贝的方法。System.arraycopy()…是这样扩容的。所以StringBuilder/StringBuffer适合于使用字符串的频繁拼接操作上。

Integer常用方法:

  • Integer有String和int构造方法
  • 除了Integer,其它的7种包装类型都有类似的构造方法
  • 8种包装类都有MAX_VALUE和MIN_VALUE方法:通过访问包装类的常量,来获取该基本数据类型的最大值和最小值
代码演示(MAX_VALUE和MIN_VALUE方法):
/*
* Integer有String和int构造方法
* 除了Integer,其它的7种包装类型都有类似的构造方法
* 8种包装类都有MAX_VALUE和MIN_VALUE方法:通过访问包装类的常量,来获取该基本数据类型的最大值和最小值*/
public class IntegerTest02 {
    public static void main(String[] args) {
        //将数字100转换成Integer包装类型
        Integer a = new Integer(100);
        //将字符串"1000"转换成Integer包装类型
        Integer b = new Integer("1000");
        System.out.println(a + "\t" + b);//100	1000

        //将double:1.314转换成Double包装类型
        Double d1 = new Double(1.314);
        //将字符串"5.201"转换成Double包装类型
        Double d2 = new Double("5.201");
        System.out.println(d1 + "\t" + d2);//1.314	5.201

        System.out.println("int的最大值:" + Integer.MAX_VALUE);//int的最大值:2147483647
        System.out.println("byte最小值:" + Byte.MIN_VALUE);//byte最小值:-128


        //自动装箱:int类型 --自动转换为-->Integer
        Integer x = 100;
    }
}

整数型常量池【-128~127】

代码演示:
/*
* 自动拆箱和自动装箱只有在加减乘除运算时才会触发*/
public class IntegerTest03 {
    public static void main(String[] args) {
        //自动装箱:将基本数据类型转换为包装类型
        Integer x = 1000;
        //自动拆箱,将包装类型转换为基本数据类型,并加1.
        System.out.println(x + 1);//1001
        Integer y = 1000;
        //"=="比较的是内存地址。
        System.out.println(x==y);//false

        /*例外:Integer面试题
        * Java中为了提高程序的执行效率,将【-128~127】之间所有的包装对象提前创建好,
        * 放到了一个方法区的“整数型常量池”中,目的时只要用这个区间的数据不需要再new了,
        * 直接从整数型常量池当中取出来。
        * 池:cache,就是缓存机制--大型项目中的重要手段
        * */
        Integer a = 127;
        Integer b = 127;
        //当数字在【-128~127】这个区间之内用==做比较,如果数据相同,则相等
        System.out.println(a == b);//true
    }
}

int,String,Integer三者之间的相互转换

代码演示:
public class IntegerTest04 {
    public static void main(String[] args) {
        //手动装箱
        Integer x = new Integer(1000);
        //手动拆箱
        int y = x.intValue();
        Integer a = new Integer("123");
        System.out.println(a);//123

        /*static int parseInt(String s)
          静态方法。传参String,返回int
          网页上输入的234实际上是一个String字符串类型*/
        int retValue = Integer.parseInt("234");
       // int retValue2 = Integer.parseInt("中文");//NumberFormatException异常
        System.out.println(retValue + 100);//334

        double retValue03 = Double.parseDouble("2.23");
        System.out.println(retValue03 + 1.1);//3.33
        
        //static Integer valueOf(int i) 静态方法
        //   返回一个表示指定的 int 值的 Integer 实例。
        //int 转换为String
        //way01
        int i = 100;
        String s = i +"";
        //String ss2 = 100 +"";//缩写版
        System.out.println(s);
        //way02
        int i2 = 100;
        String s2=String.valueOf(i);
        //String ss = String.valueOf("100");//缩写版
        System.out.println(s2);

        //String转换为int
        String s3 = "111";
        int i3 = Integer.parseInt(s3);
        //int ii2 = Integer.parseInt("111");//缩写版
        System.out.println(i3);

        //int转换为Integer 自动装箱
        //int i4 =100;
        //Integer in = i4;//100为int类型
        Integer inn = 100;//自动装箱
        System.out.println(inn);

        //Integer转换为int 自动拆箱
        Integer in2 = 100;//100为Integer类型
        int i5 = (in2);
        System.out.println(i5);

        //String转换为Integer
        String s4 = "100";
        Integer in3 = Integer.valueOf(s4);
        //Integer in5 = Integer.valueOf("100");//缩写版
        System.out.println(in3);

        //Integer转换为String
        Integer in4 = 100;
        String s5 = String.valueOf(in4);
        //String s6 = String.valueOf(100);//缩写版
        System.out.println(s5);
    }
}

二进制,八进制,十六进制的转换

以下转换进制都是静态方法,直接类名.方法即可
  static String toBinaryString(int i)
       以二进制(基数 2)无符号整数形式返回一个整数参数的字符串表示形式。
  static String toHexString(int i)
       以十六进制(基数 16)无符号整数形式返回一个整数参数的字符串表示形式。
  static String toOctalString(int i)
       以八进制(基数 8)无符号整数形式返回一个整数参数的字符串表示形式。
代码演示:
	System.out.println("二进制:"+Integer.toBinaryString(20));//二进制:10100
	System.out.println("十六进制:"+ Integer.toHexString(20));//十六进制:14
	System.out.println("八进制:" + Integer.toOctalString(20));//八进制:24

日期类

Date类有参数表示毫秒
Date类无参表示:获取系统当前时间(精确到毫秒的系统当前时间)
日期类需要用import进行调用:import java.util.Date;
用SimpleDateFormat进行日期格式化,也需要调用:import java.text.SimpleDateFormat;返回类型为String类型
代码详解:
import java.text.SimpleDateFormat;
import java.util.Date;

/*
* Java中对日期的处理*/
public class DateTest01 {
    public static void main(String[] args) throws Exception {
        //获取系统当前时间(精确到毫秒的系统当前时间)
        //直接调用无参数构造方法
        Date nowTime = new Date();
        //java.util.Date类的toString()方法已经被重写,所以输出的是日期字符串。
        System.out.println(nowTime);//Mon May 04 13:58:37 CST 2020
        //日期格式化:SimpleDateFromat
        //注意:在日期格式中,除了y M d H m s SS 不能随便写,其它的可以随意修改。
        SimpleDateFormat sdf = new SimpleDateFormat("yyy年MM月dd日   HH:mm:ss");
        String nowTimesdf = sdf.format(nowTime);
        System.out.println(nowTimesdf);

        //日期字符串String转换成Date类型
        String time = "2020-05-04  14:19";
        //注意:转换时格式必须和字符串格式一模一样,否则会出现异常
        SimpleDateFormat sdf02 = new SimpleDateFormat("yyyy-MM-dd HH:mm");
        Date dataTime = sdf02.parse(time);
        System.out.println(dataTime);

    }
}

System类的相关属性和方法:

 System类的相关属性和方法:
 System.out[out是System类的静态变量]
 System.out.prinltn()【println()方法不是System类的,是PrintStream类的方法】
 System.currentTimeMillis()获取自1970年1月日到系统当前时间的总毫秒数。
 System.exit(0)退出JVM
代码演示(currentTimeMillis()):
public class DateTest02 {
    public static void main(String[] args) {
        /* System.currentTimeMillis()无参表示:获取1970年1月1日 00:00:00到当前系统时间的总毫秒数
        * 1秒 = 1000毫秒*/
        long nowTimeMillis =System.currentTimeMillis();
        System.out.println(nowTimeMillis);
        //统计方法执行所花费的时间
        long begin = System.currentTimeMillis();
        price();
        long end = System.currentTimeMillis();
        System.out.println("花费时间为:" + (end - begin));
    }
    public static void price()
    {
        for (int i = 0; i <10000000 ; i++) {
            System.out.println(i);
        }
    }
}
代码演示:(如何准确获取某个时间点)
import java.text.SimpleDateFormat;
import java.util.Date;

public class DateTest03 {
    public static void main(String[] args) {
        //Date类有参数表示毫秒
        Date time = new Date(1);//注意:参数是毫秒
        SimpleDateFormat sdf = new SimpleDateFormat("yyy-MM-dd  HH:mm:ss SSS");
        String strTime = sdf.format(time);
        System.out.println(strTime);//1970-01-01  08:00:00 001

        //获取昨天的此时时间:现在的毫秒减去一天的毫秒
        Date time2 = new Date(System.currentTimeMillis() - (1000 * 60 *60 * 24));
        String strTime2 = sdf.format(time2);
        System.out.println(strTime2);
    }
}

数字格式化(DecimalFormat)

* java.text.DecimalFormat专门负责数字格式化
* DecimalFormat df = new DecimalFormat("数字格式");
* 数字格式:
*   #代表任意数字
*   ,代表千分位
*   .代表小数点
*   0代表不够时补0
代码演示:
import org.w3c.dom.ls.LSOutput;
import java.text.DecimalFormat;

public class DecimalFormatTest01 {
    public static void main(String[] args) {
        //"####,###,##"表示加入千分位,保留两位小数
        DecimalFormat df = new DecimalFormat("###,###.##");
        String s = df.format(1234.12312312);
        System.out.println(s);//

        DecimalFormat df2 = new DecimalFormat("####,###.0000");
        String s2 = df2.format(12345346.456);
        System.out.println(s2);
    }

}

BigDecimal (常用于财务数据)

   BigDecimal 属于大数据,精度极高。不属于基本数据类型,属于Java对象(引用基本数据类型)
    这是SUN公司提供的一个类。专门用在财务软件当中。
    java.math.BigDecimal
代码演示:
import java.math.BigDecimal;

public class BigDecimalTest01 {
    public static void main(String[] args) {
        BigDecimal b1 = new BigDecimal(100);
        BigDecimal b2 = new BigDecimal(200);
        //求和:调用方法求和:
        BigDecimal b3 = b1.add(b2);
        //减法:
        BigDecimal b5 = b2.subtract(b1);
        //乘法:
        BigDecimal b6 = b1.multiply(b2);
        //除法:
        BigDecimal b4 = b2.divide(b1);

        System.out.println("b1 + b2 =" + b3 +"\tb2 - b1 = " + b5 +"\tb1*b2 ="+b6+"\tb2/b1 =" + b4  );
        //输出结果:b1 + b2 =300	b2 - b1 = 100	b1*b2 =20000	b2/b1 =2
    }
}

Ramdom:(随机数)

代码演示:
import java.util.Random;

//随机数
public class RandomTest01 {
    public static void main(String[] args) {
        //创建随机数对象
        Random random = new Random();
        //随机产生一个int类型取值范围内的数字
        int num01 = random.nextInt();
        System.out.println(num01);
        //在【1~100】区间随机生成一个int类型的数字
        int num02 = random.nextInt(100);
        System.out.println(num02);
    }
}
练习代码:随机生成五个数,不能有相同数,如果相同则重新生成,将这五个数放在数组中
import java.util.Arrays;
import java.util.Random;
//随机数
public class RandomTest02 {
    public static void main(String[] args) {
        System.out.println("这五个随机数为:");
        ran();
    }


    public static void ran(){
        //创建数组:长度为5的int类型数组
        int[] arr = new int[5];
        //创建数组下标
        int index = 0;
        //创建随机数对象
        Random r = new Random();

        //防止数组下标0与自变量相同,给数组数据初始化值
        for (int i = 0; i <arr.length ; i++) {
            arr[i] = -1;
           // System.out.print(arr[i]);
        }
        //while循环
       while(index < arr.length){
            //随机数的范围1~6
           int a = r.nextInt(6);
            //判断是否相等
           if(boo(arr, a)){
               arr[index++] = a;
           }
        }
        for (int i = 0; i <arr.length ; i++) {
            System.out.print(arr[i] + "\t");
        }
    }
    public static boolean boo(int[] arr, int a){
        for (int i = 0; i <arr.length ; i++) {
            if (arr[i] == a){
                return false;
            }
        }
        return true;
    }
}

枚举:

枚举:一枚一枚可以列出来的,才建议使用枚举类型。
枚举编译时候生成class文件。
枚举也是一种引用数据类型
枚举中的每一个值可以看做常量
语法:
enum 枚举类型名{
    枚举值1,枚举值2,枚举值3...
}
结果超过两种的建议使用枚举,结果为两种的建议使用boolean
代码演示:
/*
例如:
* */
public class EnumTest01 {
    public static void main(String[] args) {
        enum_ee();
    }
    public static Seanson enum_ee(){
        return Seanson.SPRING;
    }
}

enum Seanson{
    //春夏秋冬
    SPRING,SUMMER,AUTUMN,WINTER
}

java异常处理机制

编译时异常与运行时异常

Object下面有Thrwoable(可抛出的)
	Throwoable下面有两个分支:Error(不可处理的,直接退出JVM)和Exception(可处理的)
		Exception下有两个分支:
			Exception的直接子类:编译时异常:要求程序员在编写程序阶段必须预先对这些异常进行处理,否则编译器报错。
			RuntimeException:运行时异常:在编写程序阶段程序员可以预先处理,也可以不管。
			编译时异常又称:受检异常(	CheckedException),受控异常
			运行时异常又称:未受检异常(UncheckedEception),非受控异常

编译时异常与运行时异常,都是发生在运行阶段,编译阶段异常是不会发生的。

编译时异常因为编译时异常必须在编译(编写)阶段预先处理,如果不处理,编译器报错,从而起名编译异常。
所有异常都是在运行阶段发生的。因为只有程序运行阶段才可以new对象,而异常的发生就是new异常对象。

编译时异常和运行时异常区别:

编译时异常发生概率比较高。
运行时异常一般发生的概率比较低。

Java语言中对异常的处理包括两种方式:

第一种方式:在方法声明的位置上,使用throws关键字,抛给上一级。
第二种方式:使用try...catch语句进行异常捕捉。

注意:只要异常没有捕捉,采用上抛的方式,此方法的后续代码不执行。

在以后的开发中,处理编译时异常,应该上报还是捕捉呢,怎么选?
    如果希望调用者来处理,选择throws上报。
    其它情况使用捕捉的方式。	
 一般不建议在main方法上使用throws,因为这个异常如果真正的发生了,一定会抛给JVM。JVM只有终止。
 异常处理机制的作用就是增强程序的健壮性。怎么能做到,异常发生了也不影响程序的执行。所以
 一般main方法中的异常建议使用try..catch进行捕捉。main就不要继续上抛了。
代码演示:
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;

public class ExceptionTest06 {
    // 一般不建议在main方法上使用throws,因为这个异常如果真正的发生了,一定会抛给JVM。JVM只有终止。
    // 异常处理机制的作用就是增强程序的健壮性。怎么能做到,异常发生了也不影响程序的执行。所以
    // 一般main方法中的异常建议使用try..catch进行捕捉。main就不要继续上抛了。
    /*
    public static void main(String[] args) throws FileNotFoundException {
        System.out.println("main begin");
        m1();
        System.out.println("main over");
    }
     */
    public static void main(String[] args) {

        // 100 / 0这是算术异常,这个异常是运行时异常,你在编译阶段,可以处理,也可以不处理。编译器不管。
        //System.out.println(100 / 0); // 不处理编译器也不管
        // 你处理也可以。
        /*
        try {
            System.out.println(100 / 0);
        } catch(ArithmeticException e){
            System.out.println("算术异常了!!!!");
        }
         */

        System.out.println("main begin");
        try {
            // try尝试
            m1();
            // 以上代码出现异常,直接进入catch语句块中执行。
            System.out.println("hello world!");
        } catch (FileNotFoundException e){ // catch后面的好像一个方法的形参。
            // 这个分支中可以使用e引用,e引用保存的内存地址是那个new出来异常对象的内存地址。
            // catch是捕捉异常之后走的分支。
            // 在catch分支中干什么?处理异常。
            System.out.println("文件不存在,可能路径错误,也可能该文件被删除了!");
            System.out.println(e); //java.io.FileNotFoundException: D:\course\01-课\学习方法.txt (系统找不到指定的路径。)
        }

        // try..catch把异常抓住之后,这里的代码会继续执行。
        System.out.println("main over");
    }

    private static void m1() throws FileNotFoundException {
        System.out.println("m1 begin");
        m2();
        // 以上代码出异常,这里是无法执行的。
        System.out.println("m1 over");
    }

    // 抛别的不行,抛ClassCastException说明你还是没有对FileNotFoundException进行处理
    //private static void m2() throws ClassCastException{
    // 抛FileNotFoundException的父对象IOException,这样是可以的。因为IOException包括FileNotFoundException
    //private static void m2() throws IOException {
    // 这样也可以,因为Exception包括所有的异常。
    //private static void m2() throws Exception{
    // throws后面也可以写多个异常,可以使用逗号隔开。
    //private static void m2() throws ClassCastException, FileNotFoundException{
    private static void m2() throws FileNotFoundException {
        System.out.println("m2 begin");
        // 编译器报错原因是:m3()方法声明位置上有:throws FileNotFoundException
        // 我们在这里调用m3()没有对异常进行预处理,所以编译报错。
        // m3();

        m3();
        // 以上如果出现异常,这里是无法执行的!
        System.out.println("m2 over");
    }

    private static void m3() throws FileNotFoundException {
        // 调用SUN jdk中某个类的构造方法。
        // 这个类还没有接触过,后期IO流的时候就知道了。
        // 我们只是借助这个类学习一下异常处理机制。
        // 创建一个输入流对象,该流指向一个文件。
        /*
        编译报错的原因是什么?
            第一:这里调用了一个构造方法:FileInputStream(String name)
            第二:这个构造方法的声明位置上有:throws FileNotFoundException
            第三:通过类的继承结构看到:FileNotFoundException父类是IOException,IOException的父类是Exception,
            最终得知,FileNotFoundException是编译时异常。

            错误原因?编译时异常要求程序员编写程序阶段必须对它进行处理,不处理编译器就报错。
         */
        //new FileInputStream("D:\\course\\01-开课\\学习方法.txt");

        // 我们采用第一种处理方式:在方法声明的位置上使用throws继续上抛。
        // 一个方法体当中的代码出现异常之后,如果上报的话,此方法结束。
        new FileInputStream("D:\\course\\01-课\\学习方法.txt");

        System.out.println("如果以上代码出异常,这里会执行吗??????????????????不会!!!");
    }
}
try…catch
try语句块中的某一行出现异常,该行后面的代码不会执行。
try...catch捕捉异常之后,后续代码可以执行。
catch后面的小括号中的类型可以时具体的异常类型,也可以是该异常类型的父类型。
catch可以写多个。建议catch的时候,精确的一个个处理,这样有利于程序调试
catch写多个时,必须从上到下,从小到大。
代码演示:
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;

/*
深入try..catch
    1、catch后面的小括号中的类型可以是具体的异常类型,也可以是该异常类型的父类型。
    2、catch可以写多个。建议catch的时候,精确的一个一个处理。这样有利于程序的调试。
    3、catch写多个的时候,从上到下,必须遵守从小到大。
 */
public class ExceptionTest07 {
    /*
    public static void main(String[] args) throws Exception, FileNotFoundException, NullPointerException {

    }
     */

    /*public static void main(String[] args) throws Exception {

    }*/

    public static void main(String[] args) {

        //编译报错
        /*try {
            FileInputStream fis = new FileInputStream("D:\\course\\02-JavaSE\\document\\JavaSE进阶讲义\\JavaSE进阶-01-面向对象.pdf");
        } catch(NullPointerException e) {

        }*/

        /*try {
            FileInputStream fis = new FileInputStream("D:\\curse\\02-JavaSE\\document\\JavaSE进阶讲义\\JavaSE进阶-01-面向对象.pdf");
            System.out.println("以上出现异常,这里无法执行!");
        } catch(FileNotFoundException e) {
            System.out.println("文件不存在!");
        }

        System.out.println("hello world!");*/

        /*try {
            FileInputStream fis = new FileInputStream("D:\\curse\\02-JavaSE\\document\\JavaSE进阶讲义\\JavaSE进阶-01-面向对象.pdf");
        } catch(IOException e) { // 多态:IOException e = new FileNotFoundException();
            System.out.println("文件不存在!");
        }*/

        /*try {
            FileInputStream fis = new FileInputStream("D:\\curse\\02-JavaSE\\document\\JavaSE进阶讲义\\JavaSE进阶-01-面向对象.pdf");
        } catch(Exception e) { // 多态:Exception e = new FileNotFoundException();
            System.out.println("文件不存在!");
        }*/

        /*try {
            //创建输入流
            FileInputStream fis = new FileInputStream("D:\\curse\\02-JavaSE\\document\\JavaSE进阶讲义\\JavaSE进阶-01-面向对象.pdf");
            //读文件
            fis.read();
        } catch(Exception e) { //所有的异常都走这个分支。
            System.out.println("文件不存在!");
        }*/

        /*try {
            //创建输入流
            FileInputStream fis = new FileInputStream("D:\\curse\\02-JavaSE\\document\\JavaSE进阶讲义\\JavaSE进阶-01-面向对象.pdf");
            //读文件
            fis.read();
        } catch(FileNotFoundException e) {
            System.out.println("文件不存在!");
        } catch(IOException e){
            System.out.println("读文件报错了!");
        }*/

        // 编译报错。
        /*
        try {
            //创建输入流
            FileInputStream fis = new FileInputStream("D:\\curse\\02-JavaSE\\document\\JavaSE进阶讲义\\JavaSE进阶-01-面向对象.pdf");
            //读文件
            fis.read();
        } catch(IOException e){
            System.out.println("读文件报错了!");
        } catch(FileNotFoundException e) {
            System.out.println("文件不存在!");
        }
         */

        // JDK8的新特性!
        try {
            //创建输入流
            FileInputStream fis = new FileInputStream("D:\\curse\\02-JavaSE\\document\\JavaSE进阶讲义\\JavaSE进阶-01-面向对象.pdf");
            // 进行数学运算
            System.out.println(100 / 0); // 这个异常是运行时异常,编写程序时可以处理,也可以不处理。
        } catch(FileNotFoundException | ArithmeticException | NullPointerException e) {
            System.out.println("文件不存在?数学异常?空指针异常?都有可能!");
        }
    }
}
异常对象重要的两个方法:(getMessage(),printStackTrace())
获取异常简单的描述信息:
    String msg = exception.getMessage();	
打印异常追踪的堆栈信息:
    exception.printStackTrace();(常用)
我们以后查看异常的追踪信息,我们应该怎么看,可以快速的调试程序呢?
    异常信息追踪信息,从上往下一行一行看。
    但是需要注意的是:SUN写的代码就不用看了(看包名就知道是自己的还是SUN的。)。
    主要的问题是出现在自己编写的代码上。
代码演示:
public class ExceptionTest08 {
    public static void main(String[] args) {
        // 这里只是为了测试getMessage()方法和printStackTrace()方法。
        // 这里只是new了异常对象,但是没有将异常对象抛出。JVM会认为这是一个普通的java对象。
        NullPointerException e = new NullPointerException("空指针异常fdsafdsafdsafds");

        // 获取异常简单描述信息:这个信息实际上就是构造方法上面String参数。
        String msg = e.getMessage(); //空指针异常fdsafdsafdsafds
        System.out.println(msg);

        // 打印异常堆栈信息
        // java后台打印异常堆栈追踪信息的时候,采用了异步线程的方式打印的。
        e.printStackTrace();

        for(int i = 0; i < 1000; i++){
            System.out.println("i = " + i);
        }

        System.out.println("Hello World!");
    }
}

final子句(关键字):

关于try..catch中的finally子句:
    1、在finally子句中的代码是最后执行的,并且是一定会执行的,即使try语句块中的代码出现了异常。
      	 	finally子句必须和try一起出现,不能单独编写。

    2、finally语句通常使用在哪些情况下呢?
	        通常在finally语句块中完成资源的释放/关闭。
	        因为finally中的代码比较有保障。
	        即使try语句块中的代码出现异常,finally中代码也会正常执行。
    3,try和finally,没有catch可以吗?可以。
            try不能单独使用。
            try finally可以联合使用。
    4,以下代码的执行顺序:
            先执行try...
            再执行finally...
            最后执行 return (return语句只要执行方法必然结束。)
代码演示:
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
public class ExceptionTest10 {
    public static void main(String[] args) {
        FileInputStream fis = null; // 声明位置放到try外面。这样在finally中才能用。
        try {
            // 创建输入流对象
            fis = new FileInputStream("D:\\course\\02-JavaSE\\document\\JavaSE进阶讲义\\JavaSE进阶-01-面向对象.pdf");
            // 开始读文件....

            String s = null;
            // 这里一定会出现空指针异常!
            s.toString();
            System.out.println("hello world!");

            // 流使用完需要关闭,因为流是占用资源的。
            // 即使以上程序出现异常,流也必须要关闭!
            // 放在这里有可能流关不了。
            //fis.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch(IOException e){
            e.printStackTrace();
        } catch(NullPointerException e) {
            e.printStackTrace();
        } finally {
            System.out.println("hello 浩克!");
            // 流的关闭放在这里比较保险。
            // finally中的代码是一定会执行的。
            // 即使try中出现了异常!
            if (fis != null) { // 避免空指针异常!
                try {
                    // close()方法有异常,采用捕捉的方式。
                    fis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

        System.out.println("hello kitty!");

    }
}

fanal面试题

代码演示:
/*
finally面试题
 */
public class ExceptionTest13 {
    public static void main(String[] args) {
        int result = m();
        System.out.println(result); //100
    }

    /*
    java语法规则(有一些规则是不能破坏的,一旦这么说了,就必须这么做!):
        java中有一条这样的规则:
            方法体中的代码必须遵循自上而下顺序依次逐行执行(亘古不变的语法!)
        java中海油一条语法规则:
            return语句一旦执行,整个方法必须结束(亘古不变的语法!)
     */
    public static int m(){
        int i = 100;
        try {
            // 这行代码出现在int i = 100;的下面,所以最终结果必须是返回100
            // return语句还必须保证是最后执行的。一旦执行,整个方法结束。
            return i;
        } finally {
            i++;
        }
    }
}

/*
反编译之后的效果
public static int m(){
    int i = 100;
    int j = i;
    i++;
    return j;
}
 */

final,finally,finalize的区别

final 关键字
    final修饰的类无法继承
    final修饰的方法无法覆盖
    final修饰的变量不能重新赋值。
finally 关键字
    和try一起联合使用。
    finally语句块中的代码是必须执行的。
finalize 标识符
    是一个Object类中的方法名。
    这个方法是由垃圾回收器GC负责调用的。
代码演示:
public class ExceptionTest14 {
    public static void main(String[] args) {

        // final是一个关键字。表示最终的。不变的。
        final int i = 100;
        //i = 200;

        // finally也是一个关键字,和try联合使用,使用在异常处理机制中
        // 在fianlly语句块中的代码是一定会执行的。
        try {

        } finally {
            System.out.println("finally....");
        }

        // finalize()是Object类中的一个方法。作为方法名出现。
        // 所以finalize是标识符。
        // finalize()方法是JVM的GC垃圾回收器负责调用。
        Object obj;
    }
}

// final修饰的类无法继承
final class A {
    // 常量。
    public static final double MATH_PI = 3.1415926;
}

class B {
    // final修饰的方法无法覆盖
    public final void doSome(){

    }
}

自定义异常类

    第一步:编写一个类继承Exception或者RuntimeException.
    第二步:提供两个构造方法,一个无参数的,一个带有String参数的。
代码演示:
public class MyException extends Exception{ // 编译时异常
    public MyException(){

    }
    public MyException(String s){
        super(s);
    }
}

/*
public class MyException extends RuntimeException{ // 运行时异常

}
 */

综合训练

题目:
 开放型题目,随意发挥:
	写一个类Army,代表一支军队,这个类有一个属性Weapon数组w(用来存储该军队所拥有的所有武器),
	该类还提供一个构造方法,在构造方法里通过传一个int类型的参数来限定该类所能拥有的最大武器数量,
	并用这一大小来初始化数组w。	
	该类还提供一个方法addWeapon(Weapon wa),表示把参数wa所代表的武器加入到数组w中。
	在这个类中还定义两个方法attackAll()让w数组中的所有武器攻击;
	以及moveAll()让w数组中的所有可移动的武器移动。 
	
	写一个主方法去测试以上程序。 
	提示:
		Weapon是一个父类。应该有很多子武器。
		这些子武器应该有一些是可移动的,有一些
		是可攻击的。
代码演示:
package com.bjpowernode.javase.array;

public class HomeWork03 {
    public static void main(String[] args) {
        Army army = new Army(5);
        //多态:父类型引用指向子类型对象
        Weapon weapon1 = new Tank();
        Weapon weapon2 = new yunshuji();
        Weapon weapon3 = new buqiang();
        try {
            army.addWeapon(weapon1);
            army.addWeapon(weapon2);
            army.addWeapon(weapon3);
        }catch (myException m){
            System.out.println(m.getMessage());
        }
        army.moveAll();
        army.attackAll();
    }
}

//创建一个Army类代表军队
class Army {
    //创建一个Weapon属性的数组w
    Weapon[] w;
    //通过构造方法限定Army类所能拥有的最大化武器数量,同时初始化w。
    public Army(int count) {
       w = new Weapon[count];
    }

    //addWeapon(Weapon wa)方法将wa和数组相关联
    public void addWeapon(Weapon wa) throws myException{
        for (int i = 0; i <w.length ; i++) {
            if(w[i] == null){
                w[i] = wa;
                System.out.println(wa + "武器添加成功");
                return;
            }
        }
        throw new myException("警告!能源耗尽!");
    }
//定义attackAll()方法,遍历w攻击。
    public void attackAll(){
        for (int i = 0; i <w.length ; i++) {
            if (w[i] instanceof Attack){
                Attack attack = (Attack)w[i];
                attack.attack();
            }
        }
    }
//定义moveAll()方法,遍历w移动
    public void moveAll(){
        for (int i = 0; i <w.length ; i++) {
            if(w[i] instanceof Moveable){
                Moveable moveable = (Moveable)w[i];
                moveable.move();
            }
        }
    }
}

//定义一个接口
interface Moveable{
    void move();
}

interface Attack{
    void attack();
}

class Weapon{
}

class Tank extends Weapon implements Moveable,Attack{

    @Override
    public void move() {
        System.out.println("坦克移动");
    }

    @Override
    public void attack() {
        System.out.println("坦克攻击");
    }

    @Override
    public String toString() {
        return "坦克";
    }
}

class yunshuji extends Weapon implements Moveable{

    @Override
    public void move() {
        System.out.println("运输机移动");
    }
    //重写toString
    public String toString(){
        return "运输机";
    }
}

class buqiang extends Weapon implements  Attack{

    @Override
    public void attack() {
        System.out.println("步枪攻击");
    }
    //重写toString方法
    public String toString()
    {
        return "步枪";
    }
}

class myException extends Exception{
    public myException() {
    }

    public myException(String message) {
        super(message);
    }
}

转载:https://blog.csdn.net/weixin_45144691/article/details/105599288
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场