目录
1、类变量(静态类变量)
1、为什么要有静态类变量?
引出:
过年,公司发过年礼品,假设我们有一个礼品类Gift,有一个发放礼品的类方法receive(),我想知道当前有多少个员工领取礼品,怎么办?
解决:
1、在类中定义一个属性count,然后在receive()里每调用该方法进行conut++?
2、在main方法定义一个count局部变量,每调用一次receive()进行count++?
3、在类中定义一个静态的类变量,在方法receive()中进行count++?
答案:选择3!第一种不管领取了多少礼品,每个对象中的count属性值都是1;第二种可以是可以,但不符合oop的思想,如果需要在别的地方用到该count值,没办法调用啊;第三种,静态类变量多个对象共享该变量,不管是用那个对象获取的count值,都是最新的且一致的!
#测试代码:
public class StaticDemo {
public static void main(String[] args) {
Gift gift = new Gift("张三");
Gift gift1 = new Gift("李四");
gift.receive();
System.out.println("当前有"+Gift.count+"个员工领取了礼品"+" 名字分别为:"+ Gift.str);
gift1.receive();
System.out.println("当前有"+gift1.count+"个员工领取了礼品"+" 名字分别为:"+ Gift.str);
}
}
//礼品类
class Gift{
private String name;
protected static int count;
public static String str="";
public Gift(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
//发放礼品
public void receive(){
giftEliminate();
count++;
str = str.concat(getName());
}
//当领取人数大于5个我就调用该方法将count清零;
public void giftEliminate(){
if (count>5){
Gift.count = 0;
}
}
}
输出:
当前有1个员工领取了礼品 名字分别为:张三
当前有2个员工领取了礼品 名字分别为:张三李四
小结(什么时候使用类变量?):
1、静态类变量的作用就是存储一些独立于对象的数据,但各对象又能共享该变量值
2、如何定义和使用静态类变量?
定义:
1、static public int count
2、public static int count (推荐使用)
#从上面代码可以看出,在普通属性上声明一个static关键字,静态类方法也是如此
使用:
1、使用类名.变量名(推荐使用) Gift.count
2、对象名.变量名 gift1.count
3、类变量于实例变量(普通类属性)的区别?
1、类变量属于类,但被所有对象共享
2、实例变量只属于这一个对象,独立不被共享
4 小结:
类变量:
1、使用关键字static声明定义,推荐定义格式: 修饰符 static 数据类型 变量名
2、使用类名.变量名调用该类变量
3、被所有对象共享变量值
实例变量:
1、定义:修饰符 数据类型 变量名
2、使用对象名.变量名调用该变量
3、只属于该对象本身,不被共享
2、静态方法
1、为什么要有静态方法?
应用:
当我们要写一个方法操作一些跟对象无关的数据时,可以使用静态方法。
2、静态方法的定义和使用
定义:
1、public static void print(){}
2、static void print(){}
修饰符 static 返回数据类型 方法名(){}
#注意:因为修饰方法的修饰符只有public 或 默认(不写)
使用:
1、类名.方法名() (推荐使用)
2、对象名.方法名()
代码:
public class StaticDemo {
public static void main(String[] args) {
Student student = new Student("张三");
Student student1 = new Student("李四");
Student.count_study_money(3000);
Student.count_study_money(5000);
System.out.println("当前学费共交了"+Student.get_study_money()+"元");
student.print();
}
}
class Student{
public String name;
private static double study_money;
static String str="";
public Student(String name){
super();
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
//计算学费
public static void count_study_money(double study_money){
//Student.study_money = Student.study_money + study_money;
Student.study_money += study_money;
}
//返回学费
public static double get_study_money(){
return Student.study_money;
}
public void print(){
System.out.println(get_study_money());//非静态方法中调用静态方法
System.out.println(name);//非静态方法中调用非静态变量
System.out.println(str);//非静态方法中调用静态变量
}
}
输出:
当前学费共交了8000.0元
8000.0
张三
3、使用类方法时,有哪些要注意的细节?
1、类方法中不能使用this和super与对象相关的关键字。 因为this代表调用者当前对象本身,而静态方法执行是无需实例化对象,那这个this就是空,所以静态方法中不能用this
2、类方法和类变量调用跟对象是否创建无关,调用时都是通过类名.类变量/类方法()调用
3、而对象变量和对象方法与实例对象有关,调用对象方法和对象变量时只能用对象名.变量 或 对象名.方法名(),不能使用类名.方法和变量!
4、静态(类)方法中只能调用静态(类)变量和静态方法,无法使用非静态变量和非静态方法
5、非静态方法可以调用非静态变量、非静态方法、静态方法、静态变量
i
3、Main()方法
public static void main(String[] args){}
1、为什么main()方法要这样写?
# 因为有了public权限,所以jvm才能调用main;
因为有了static,所以调用mian()方法时不需要有对象创建;
因为有了String[] args字符串数组,所以运行main里面的程序时,可以用字符串数组去存储中转所需的参数!
4、代码块
1、代码块的定义
1、普通代码块
格式:{代码体}
2、静态代码块
static{代码体}
2、普通代码与静态代码块的使用区别
普通代码块:
1、是对对象进行初始化。每创建一次对象就执行一次
静态代码块:
1、是对类进行初始化。随着类被加载的时候就执行了,且只会执行一次(不管new几个对象)
#代码验证:
//午餐类
class Lunch{
public static double price=20;
//普通代码块
{
System.out.println("普通代码块:先煮饭,洗菜,炒菜");
}
//静态代码块
static {
System.out.println("静态代码块:先煮饭,洗菜,炒菜");
}
//无参构造器
public Lunch() {
System.out.println("这是无参构造器");
}
//静态方法
public static void makeLunch(){
System.out.println("这是一个静态方法");
}
}
public class codeBlock {
public static void main(String[] args) {
Lunch lunch = new Lunch();
Lunch lunch1 = new Lunch();
Lunch lunch2 = new Lunch();
Lunch.makeLunch();
System.out.println(Lunch.price);
}
}
输出:
静态代码块:先煮饭,洗菜,炒菜
普通代码块:先煮饭,洗菜,炒菜
这是无参构造器
普通代码块:先煮饭,洗菜,炒菜
这是无参构造器
普通代码块:先煮饭,洗菜,炒菜
这是无参构造器
这是一个静态方法
20.0
说明:
1、执行顺序: 静态代码块——》普通代码块——》构造器
2、执行次数:静态代码块只执行一次,普通代码块执行次数跟对象创建次数一样
3、静态方法调用一次就执行一次
3、触发类加载的几种情况(静态代码块)
1、创建对象实例时
2、当创建子类对象实例时,先加载父类,再加载子类
3、使用类的静态成员(静态属性、静态方法)
4、还有一种是反射( 我还没学>_<...)
#代码验证:
public class codeBlock02 {
public static void main(String[] args) {
new CC();
//1、创建对象实例时会触发类加载,执行静态代码块。
//2、当创建子类对象实例时,当前类CC向上的所有父类AA、BB类都会触发类加载,从而执行对应类的静态代码块
//System.out.println(CC.str);
//1、当调用静态成员(静态方法和变量)时,会触发类加载,执行静态代码块内容
}
}
class AA{
//普通代码块
{
System.out.println("普通代码块AA");
}
//静态代码块
static {
System.out.println("静态代码块AA");
}
}
class BB extends AA{
//普通代码块
{
System.out.println("普通代码块BB");
}
//静态代码块
static {
System.out.println("静态代码块BB");
}
}
class CC extends BB{
public static String str="这是静态变量";
//普通代码块
{
System.out.println("普通代码块CC");
}
//静态代码块
static {
System.out.println("静态代码块CC");
}
public CC() {
System.out.println("这是CC的无参构造器");
}
}
执行new CC()输出:
静态代码块AA
静态代码块BB
静态代码块CC
普通代码块AA
普通代码块BB
普通代码块CC
这是CC的无参构造器
执行System.out.println(CC.str)输出:
静态代码块AA
静态代码块BB
静态代码块CC
这是静态变量
说明:上面结论是正确的!
4、创建一个类对象时,类中静态代码块、静态变量、普通代码块、普通变量、构造器的执行顺序是什么?
上代码测试:
public class codeBlock02 {
public static void main(String[] args) {
AA aa = new AA();
}
}
class AA{
//普通变量
public int numb = getNumb();
//静态类变量
public static String str=getStr();
//普通方法
public int getNumb(){
System.out.println("getNumb被执行了");
return 10;
}
//静态方法
public static String getStr(){
System.out.println("getStr()方法被执行");
return "类变量";
}
//构造器
public AA(){
super();//当有父类时会执行,没有不执行 <1>
<2>
System.out.println("这是AA的无参构造器"); <3>
}
// 在<2>这里我感觉隐藏了调用普通代码块的引用代码,因为每new一个对象时,执行顺序都是: <1> ---> <2> ---> <3>;
//普通代码块
{ System.out.println("普通代码块AA");}
//静态代码块
static {System.out.println("静态代码块AA");}
}
//输出:
// getStr()方法被执行 ---》静态类变量
// 静态代码块AA ---》静态代码块
// getNumb被执行了 ---》普通类变量
// 普通代码块AA ---》普通代码块
// 这是AA的无参构造器 ---》构造器
说明什么?
1、先执行静态static的静态代码块或静态类变量,这两优先级一样,执行顺序就看定义的位置谁先谁后
2、然后执行普通代码块或普通类变量,这两优先级也一样,执行顺序就看定义的位置谁先谁后
3、最后执行构造器
4、在构造器中super()下面还隐藏了一段看不见的调用普通代码块的引用代码
5、小练习(代码块)
#请问以下代码输出什么?
public class codeBlock01 {
public static void main(String[] args) {
new B();
}
}
class A{
//静态属性
public static int number_A = getA1();
//静态代码块
static { System.out.println("A类静态代码块");}
//普通代码块
{ System.out.println("A类普通代码块"); }
//普通属性
public int age_A = getA2();
//父类构造方法
public A(){
System.out.println("打印A类构造器");
}
public static int getA1(){
System.out.println("调用了getA1方法");
return 20;
}
public int getA2(){
System.out.println("调用了getA2方法");
return 31;
}
}
class B extends A{
//静态代码块
static { System.out.println("B类的静态代码块"); }
//静态属性
public static String getStringB1 = getB1();
//普通代码块
{ System.out.println("B类的普通代码块"); }
//普通属性
public String getStringB2 = getB2();
//子类构造方法
public B(){
super();
System.out.println("打印A类构造器");
}
public static String getB1(){
System.out.println("调用了getB1方法");
return "B1";
}
public String getB2(){
System.out.println("调用了getB2方法");
return "B2";
}
}
输出:
调用了getA1方法
A类静态代码块
B类的静态代码块
调用了getB1方法
A类普通代码块
调用了getA2方法
打印A类构造器
B类的普通代码块
调用了getB2方法
打印A类构造器
6、小练习
以下程序会输出?
public class Test {
static String s = "琳";
static {
String s = "丽";
System.out.println(s); // <1> 静态代码块最先执行,输出丽
}
public static void main(String[] args) {
new Son(s); //把"琳"传进去
}
}
class Father{
static int m=100;
public Father(){ m=999;} //父类的m=999,不改变静态变量m的值
static {
m=10000;
System.out.println("父类"+m);} // <2> 输出:父类10000
}
class Son extends Father{
int m;
{ super.m=5;} //这里修改了父类属性m=5
static {
System.out.println("static block"); //<3> 输出:static block
}
public Son(String name){
System.out.println(name); //<4> 输出: "琳"
System.out.println(m); <5> 输出: 子类属性没有赋值,所以m=0;
System.out.println(super.m); <6>输出: 5
}
}
最终输出:丽,父类10000,static block,"琳",0,5
5、单例模式
# 使用静态方法和静态属性实现单例模式
# 单例模式特点:一点创建了一个对象,之后就无法创建新对象,一个类只能有一个对象实例
#思路
1、限制创建对象
2、判断是否已经存在一个对象实例
代码实现:
public class SingletonMode {
public static void main(String[] args) {
//固定式
Singleton1 singleton1 = Singleton1.getSingleton();
Singleton1 singleton2 = Singleton1.getSingleton();
System.out.println(singleton1==singleton2);//返回true,说明成功了
//灵活式
Singleton2 singleton3 = Singleton2.getSingleton("小花");
Singleton2 singleton4 = Singleton2.getSingleton("小梅");
System.out.println(singleton3==singleton4);//返回true,说明成功了
/*
实现单例模式
思路:
1、限制创建新对象
2、判断该类中是否已经存在一个对象实例
*/
}
}
//实现一:固定式
class Singleton1{ //缺点就是:这个name参数值在编写时必须写死,那有没有自己传参值来new一个呢,看下一个
private String name;
private static Singleton1 singleton = new Singleton1("小琳");
//私有化构造器
private Singleton1(String name){
super();
this.name =name;
}
//提供一个static方法获取对象
public static Singleton1 getSingleton(){
return singleton;
}
}
//实现二:灵活式 可以自定义单例对象的数值
class Singleton2{
private String name;
private static Singleton2 Singleton;
//私有化构造器
private Singleton2(String name){
super();
this.name = name;
}
//提供一个判断对象是否存在且可以返回对象的方法
public static Singleton2 getSingleton(String name){
//判断当前是否存在对象
if (Singleton == null){
return Singleton = new Singleton2(name);
}
return Singleton;
}
}
小结(固定式和灵活式的区别):
对象创建时间上:
固定式是在类加载时就创建了该对象,而灵活式要调用才会创建对象
资源浪费上:
固定式有可能创建后就没有用过所以存在浪费资源的可能,而灵活式就不会有这情况
灵活度上:
固定式是在编写代码时对象就确定了,后续不能改变,而灵活式可以在第一次创建对象时选择创建的对象值
线程安全上:
固定式是线程安全的,灵活式是线程不安全的!
6、抽象类
6.1、抽象类的介绍
1、抽象类定义
访问修饰符 abstract 类名{ }//没有类实现
2、抽象方法定义
访问修饰符 abstract 方法名(参数列表)//没有方法体
3、抽象类的价值更多的体现在设计层面,设计者设计好抽象类让子类继承并实现抽象类的功能,更多的是充当一个模板的作用,应用场景更多体现在设计模式和框架上!
6.2、抽象类的特点
1、抽象类不能被实例化创建
2、抽象类中,可以有抽象方法,也可以没有抽象方法
3、一个方法一旦声明了成抽象方法,该方法的类也必须声明为抽象类!总结:抽象类不一定有抽象方法,但有抽象方法的类一定是抽象类
4、abstract只能修饰类和方法,不能修饰类属性(只有抽象类和方法之说,没有抽象属性之说)
5、普通类里可以有的抽象类都可以有(如静态方法、静态属性、静态代码块、普通代码块),普通类里没有的抽象方法抽象类有!
6、抽象方法没有方法体
7、如果一个类继承了抽象类,那就必须实现该抽象类的所有抽象方法,除非把自己也声明为抽象类!
8、抽象方法不能使用private、final、static修饰。
#因为抽象方法定义后必须实现,而重写也是一种实现的方式,private私有化不能被重写,final不能被继承也就无法重写,static静态化方法只跟类相关,没有对象去实现这个抽象方法,重写是跟对象相关的!
6.3、多态在抽象类的体现
1、多态参数:
[抽象父类的引用也可以指向继承它的所有子类对象,所以可以使用抽象父类的引用作为形参去接收传递过来的所有子类对象参数] 什么意思?看下面代码
代码:
----------------------------------------------------------------------------------------
/* 验证:
多态参数:接收子类对象
多态数组:存储各个子类对象
*/
//抽象父类-宠物类
abstract class Pets{
private String name;
public Pets(String name) {
super();
this.name = name;
System.out.println(name);
}
}
//宠物狗类
class petsDog extends Pets{
public petsDog(String name){
super(name);
}
}
//宠物猫类
class petsCat extends Pets{
public petsCat(String name){
super(name);
}
}
//测试类
public class Abstract01 {
public static void main(String[] args) {
Pets cat = new petsCat("加菲猫");
Pets dog = new petsDog("旺财");
//抽象父类引用Pets可以作为形参接收petsCat("加菲猫")和petsDog("旺财")
// 这两个子类对象实例,就证明了抽象类也具有多态参数的特性
}
}
输出:
加菲猫
旺财
2、多态数组:
[抽象父类也可以存放所有继承的子类对象]什么意思?看下面代码
代码:
/* 验证:
多态参数:接收子类对象
多态数组:存储各个子类对象
*/
//抽象父类-宠物类
abstract class Pets{
private String name;
public Pets(String name) {
super();
this.name = name;
System.out.println(name);
}
public String getName(){
return name;
}
//定义一个公有的抽象方法play(),玩
public abstract void play();
}
//宠物狗类
class petsDog extends Pets{
public petsDog(String name){
super(name);
}
//重写实现play()方法
@Override
public void play() {
System.out.println(getName()+"可以拿来撸");
}
//狗特有行为:看大门
public void guardHome(){
System.out.println(getName()+"会帮主人看家");
}
}
//宠物猫类
class petsCat extends Pets{
public petsCat(String name){
super(name);
}
@Override
public void play(){
System.out.println(getName()+"可以拿来撸");
}
//猫特有行为:抓老鼠
public void captureMouse(){
System.out.println(getName()+"会抓老鼠");
}
}
//测试类
public class Abstract01 {
public static void main(String[] args) {
//在这里定义一个抽象父类Pets数组,去接收不同的子类对象
Pets[] pets = new Pets[]{new petsCat("加菲猫"),new petsDog("旺财"),};
//抽象父类引用pets去接收并存储 new petsCat("加菲猫") 和 new petsDog("旺财")子类对象,运行时会进行动态绑定!
new Abstract01().getObject(pets);
}
//定义一个判断子类对象类型的方法,并打印出对象对应的特有方法
public void getObject(Pets[] abs){
//使用instanceof进行子类对象类型判断
for (Pets p:abs){
if (p instanceof petsCat){
((petsCat)p).captureMouse();
}else { //因为抽象父类无法被实例化,所以不可能会有父类的对象出现,对象只可能两种类型
((petsDog) p).guardHome();
}
}
}
}
6.4、抽象类体现了模板设计模式
1、抽象充当了多个子类的通用模板,子类可以在继承抽象类的基础上进行扩展,但子类中还是保留一定的抽象父类的行为方法
2、什么是模板设计模式?
#当有一部分功能是确定的,一部分功能是不确定的,可以用模板设计模式设计一个抽象父类,里面定义一个抽象方法,这个抽象方法做不确定功能,确定的功能在抽象父类写一个方法实现好;然后让子类继承并实现这个功能不确定的抽象方法
上代码演示:
3、需求:我想要一个抽象类,用于计算一个方法执行的时间(什么方法不确定,但是用于计算时间的方法确定)
//抽象计算类
//抽象计算类
abstract class Calculation{
//抽象方法
abstract public void Method();
//计算耗时的方法
public void consumeTime(){
long start_time = System.currentTimeMillis();
Method();
long end_time = System.currentTimeMillis();
System.out.println("该方法耗时为:"+(end_time-start_time));
}
}
class Son1 extends Calculation{
@Override
public void Method(){
String str = "";
for (int i = 0; i < 100000; i++) {
str += "SB";
}
}
}
class Son2 extends Calculation{
@Override
public void Method(){
StringBuffer str = new StringBuffer("");
for (int i = 0; i < 100000; i++) {
str.append("SB");
}
}
}
class Son3 extends Calculation{
@Override
public void Method(){
StringBuilder str = new StringBuilder("");
for (int i = 0; i < 100000; i++) {
str.append("SB");
}
}
}
//测试类
public class Template {
public static void main(String[] args) {
//实现一:
//new Son1().consumeTime();
//son1先找自己consumeTime方法,没有就找父类consumeTime方法,
// 父类consumeTime根据动态绑定调用自己的Method方法
//new Son2().consumeTime();
//new Son3().consumeTime();
//实现二:
Template.test(new Son1()); //调用静态方法:类名.方法名
new Template().test(new Son2());//调用静态方法:对象.方法名
test(new Son3()); //因为该方法在同类中,直接方法名
}
public static void test(Calculation c){
c.consumeTime();
}
}
输出:
该方法耗时为:12139
该方法耗时为:3
该方法耗时为:2
//说明字符串拼接操作效率:StringBuilder > StringBuffer > String;
7、接口
1、接口介绍:
就是把一些没有实现的方法通过接口封装到一起,当哪个类需要使用到接口的方法的时候,该类根据需求再具体去实现接口里的方法
接口定义格式:
interface 接口名{
属性
抽象方法(接口里的方法默认是abstract抽象的)
在jdk1.8后,接口里可以有 静态方法 和 默认方法的实现
}
实现接口格式:
class 类名 implements 接口名{
//可以有自己的属性和方法,但是必须实现(重写)接口的所有方法,可以跟接口隔离原则去优化
自己属性
自己方法
必须实现接口的抽象方法
}
#栗子:
//接口
interface interfaceDemo{
//接口里的属性必须定义时给定初始值
public String str="111";
//等同public static final String str = "111"
//静态方法
public static void print01(){
System.out.println("静态方法");
}
//默认方法
public default void pint02(){
System.out.println("默认方法");
}
//抽象方法
void absMethod1();
void absMethod2();
}
//测试类
public class Interface02 {
public static void main(String[] args) {
//接口里的静态方法直接用接口名调用,跟类的静态方法调用一样
interfaceDemo.print01();
//默认方法接口自己无法使用接口名调用
//interfaceDemo.print02();
}
}
//普通类
class Ordinary implements interfaceDemo{
//实现一个抽象方法1还是报错,接着实现方法2报错,实现默认方法后不报错,说明要全部实现(包含默认方法)
@Override
void pint02() { //一旦我把print2方法的改为默认,就报错,而根据实现接口的子类方法访问权限必须 >= 接口抽象方法的访问权限,
//那就证明接口的抽象方法的访问权限默认是public
}
@Override
public void absMethod1() {
}
@Override
public void absMethod2() {
}
}
//抽象类
abstract class absClass implements interfaceDemo{
//不报错,说明抽象类可以不用实现接口的抽象方法
}
//测试类
public class Interface02 {
public static void main(String[] args) {
//接口里的静态方法直接用接口名调用,跟类的静态方法调用一样
interfaceDemo.print01();
//默认方法接口自己无法使用接口名调用,只能给实现了接口的子类调用
//interfaceDemo.print02();
}
}
小细节:
1、在jdk1.8后,接口里可以有 静态方法 和 默认方法的实现 及定义接口自己属性
2、接口里的属性必须定义时给定初始值,等同于常量属性
3、接口里的静态方法直接用接口名调用,跟类的静态方法调用一样
4、默认方法接口自己无法使用接口名调用,只能给实现了接口的子类调用
5、实现接口的子类方法权限 >= 接口的抽象方法访问权限
6、抽象类可以实现接口,但可以实现接口的抽象方法
7、接口可以继承别的接口,但是不能继承普通类,当然也包含抽象类
//注意:
1、当多个接口里如果有重名的抽象方法,不会影响使用,如果是重名的常量属性时,调用时使用接口名.属性名区分
7.2、继承与接口在应用上有什么区别?
1、接口其实是对java单继承缺点的一种弥补和扩展,让子类有更丰富的方法和属性,而这些属性来源于子类实现接口里的抽象方法!
#栗子
package P3;
//猴子父类
class Monkey{
private String name;
public Monkey(String name){
this.name = name;
}
public String getName(){
return name;
}
//爬树
public void climbTree(){
System.out.println(getName()+"会爬树");
}
}
//想要给悟空加技能,会上天飞,会下海潜,使用实现接口的抽象方法
interface FlightClass{
public void flight();//会飞行
}
interface DivingClass{
public void diving();//会潜水
}
//孙悟空类
class sunMonkey extends Monkey implements DivingClass,FlightClass{
public sunMonkey(String name) {
super(name);
}
@Override
public void climbTree() {
super.climbTree();
}
//实现飞行和潜水方法
@Override
public void diving(){
System.out.println(getName()+"会潜水");
}
@Override
public void flight(){
System.out.println(getName()+"会飞行");
}
}
//测试类
public class Relation {
public static void main(String[] args) {
new sunMonkey("孙悟空").diving();
new sunMonkey("孙悟空").flight();
new sunMonkey("孙悟空").climbTree();
//接口多态,跟普通类多态一样具有多态参数和多态数组特性
test1(new sunMonkey("孙大圣"));
test2(new sunMonkey("孙大圣"));
test3(new sunMonkey("孙大圣"));
}
//在别的类的方法中去接收父类对象和实现接口方法的对象,这就是多态
public static void test1(Monkey monkey){
monkey.climbTree();
}
public static void test2(DivingClass divingClass){
divingClass.diving();
}
public static void test3(FlightClass flightClass){
flightClass.flight();
}
}
输出:
孙悟空会潜水
孙悟空会飞行
孙悟空会爬树
孙大圣会爬树
孙大圣会潜水
孙大圣会飞行
7.3、接口的多态性
# 接口的多态跟类的多态差不多,也有多态参数和多态数组的特性
1、多态参数 与 多态数组
代码举栗:
package P3;
import org.omg.CORBA.PUBLIC_MEMBER;
//游戏接口
interface IGame{
public void loading();
public void start();
public void end();
}
//游戏类
class Game{
private String gameName;
public Game(){};
public Game(String gameName){ this.gameName = gameName;}
public String getGameName(){ return gameName;}
//游戏运行
public void runGame(IGame iGame){
//这里使用接口引用去接收实现该接口的类的对象,体现了接口的多态参数
iGame.loading();
iGame.start();
iGame.end();
}
}
//LOL
class LOL extends Game implements IGame {
public LOL(){}
public LOL(String gameName){ super(gameName);}
@Override
public void loading() {
System.out.println(getGameName()+"正在加载....");
}
@Override
public void start() {
System.out.println(getGameName()+"加载完成,可以开始游戏啦....");
}
@Override
public void end() {
System.out.println(getGameName()+"正在关闭游戏....");
}
//独特方法
public void lolObject(){
System.out.println(getGameName()+"是5v5推塔游戏");
}
}
//CF
class CF extends Game implements IGame{
public CF(){}
public CF(String gameName) {
super(gameName);
}
@Override
public void loading() {
System.out.println(getGameName()+"正在加载....");
}
@Override
public void start() {
System.out.println(getGameName()+"加载完成,可以开始游戏啦....");
}
@Override
public void end() {
System.out.println(getGameName()+"正在关闭游戏....");
}
//独特方法
public void cfObject(){
System.out.println(getGameName()+"是多人枪战游戏");
}
}
//测试类
public class Relation {
public static void main(String[] args) {
//接口多态参数的体现
Game game = new Game("LOL");
game.runGame(new LOL("LOL"));
game.runGame(new CF("CF"));
System.out.println("----------------------");
//接口多态数组的体现
IGame[] iGames = new IGame[]{new LOL("英雄联盟"),new CF("穿越火线")};
for (IGame i: iGames) {
if (i instanceof LOL){
//如果想调用子类对象的独特方法,可以使用instanceof进行对象类型判断,
((LOL) i).lolObject();
}else { ((CF)i).cfObject();}
}
}
}
输出:
LOL正在加载....
LOL加载完成,可以开始游戏啦....
LOL正在关闭游戏....
CF正在加载....
CF加载完成,可以开始游戏啦....
CF正在关闭游戏....
----------------------
英雄联盟是5v5推塔游戏
穿越火线是多人枪战游戏
2、接口存在多态传递特性
代码举栗:
package p4;
import com.sun.xml.internal.ws.api.model.wsdl.WSDLOutput;
//测试类
public class Interface{
public static void main(String[] args) {
Son son = new Son();
//这是实现了子接口Ison的子类Son对象
ISon iSon = son;
//这里可以把son对象赋值给子接口ISon的引用,说明子接口引用是可以指向并接收Son类对象的
IFather iFather = son;
//这里可以把son对象赋值给父接口IFather的引用,说明父接口引用是可以指向并接收Son类对象的
Father father = son;
//这里可以把son对象赋值给父类Father的引用,说明父类引用是可以指向并接收Son类对象的
}
}
//父接口
interface IFather{
public void father();
}
//子接口
interface ISon extends IFather{
public void son();
}
//父类
class Father {
public void print(){
System.out.println("这是父类的print()方法");
}
}
//子类
class Son extends Father implements ISon{
@Override
public void son(){
System.out.println("这是子接口的son()方法");
}
@Override
public void father(){
System.out.println("这是父接口的father()方法");
}
}
小结:
1、当一个接口B继承接口A,而子类b继承父类a,而b实现接口B方法时,b类对象可以传递给接口B的所有父接口的接口引用,这就是接口的多层传递
3、多态参数与多态数组在使用上的区别?
1、多态数组在程序运行时,所有继承的子类对象或实现接口抽象方法的类对象,可以以数组的方式同时传递多个对象给父类引用
2、而参数多态只能同时传递一种类对象
3、所以当需要使用多个不同类对象时,使用多态数组;反之,使用多态参数就可以了
4、小练习
//课后小练习:以下程序输出什么?如有错误,请修改
interface A{ int a = 0;}
class B{ int a = 1;}
class C extends B implements A{
public void method1(){
System.out.println(a);
}
public static void main(String[] args) {
new C().method1();
}
}
解:
错误:调用a会有歧义。如果想调用接口的a,使用接口名A.a ; 如果想用B类的a,使用super.a
8、内部类
8.1 、内部类介绍
1、内部类介绍:
#一个类中有嵌入一个完整的类结构,这个嵌套的类称为内部类
内部类特点:
1、内部类可以直接访问外层类的私有属性
2、内部类的作用域在它的外部类中
3、本质上其实也是外部类的一个成员,其他都一样
内部类定义格式:
class Outer{ //外部类
class Inner{ //内部类
public void Method1(){
class Inner01{} //方法里的内部类
}
}
}
调用内部类格式:
new 外部类().new 内部类().内部类方法名或属性
代码举栗:
//外部类
class A{
private int a = 1;
private void A(){
System.out.println("这是外层类的A方法");
}
//内部类
class Inner{
public void print(){
System.out.println(a);
}
}
public static void main(String[] args) {
new A().new Inner().print();
}
}
输出:
1
2、内部类的分类:
*在外部类的方法中
1、局部内部类(有类名)
2、匿名内部类(没有类名,这是重点,常用)
*类似外部类的成员类
1、成员内部类(没用static修饰)
2、静态内部类(用static修饰)
8.2、局部内部类
1、局部内部类的介绍:
访问权限: 可以访问外部类所有成员和自己的成员
位置: 定义在外部类的方法或代码块中
修饰符: 只能使用final常量修饰符,因为它的作用域仅限于局部方法中,局部变量不能用修饰符,但final可以
作用域: 仅在外部类的方法或代码块中
#使用局部内部类举栗:
//外部类
class A{
private int a = 1;
public void f1(){
//外部类访问局部内部类
};
//外部类
class C1{ public void m1(){}};
private void print(){
class LocalInnerClass{
public void LocalInnerMethod(){
System.out.println("这是局部内部类的方法");
//局部内部类-->访问-->外部类成员-->直接访问
f1();
System.out.println(a);
}
}
//如果想在外部类调用局部内部类里的方法,这里得先这样
new LocalInnerClass().LocalInnerMethod();
}
public static void main(String[] args) {
new A().print();
}
}
8.3、匿名内部类
1、匿名内部类的介绍
方式一(使用接口名new)、
//接口
interface Interface1{
public void print();
}
class Anonymous {
public void Method() {
/*这是匿名内部类方式一、
* 解读:
*1、编译类型是接口Interface1,
*2、运行类型是:
* new Interface1() {
@Override
public void print() {
System.out.println("这是匿名内部类");
}
};
* 3、匿名内部类是一个对象,也相当于实现接口Interface1的无名子类
* */
Interface1 i = new Interface1() {
@Override
public void print() {
System.out.println("这是匿名内部类");
}
};
i.print();
}
//测试
public static void main(String[] args) {
new Anonymous().Method();
}
}
方式二(使用类名new)、
package p4;
//接口
interface Interface1{
public void print();
}
class FatherClass{
public void test(){}
}
class Anonymous {
public void Method() {
/*这是匿名内部类方式一、
* 解读:
*1、可以理解为:相当于接口Interface1的子类的实例对象
*2、编译类型是接口Interface1,
*3、运行类型是: class p4.Anonymous$1 表示Anonymous编号为1的内部类
Interface1() {
@Override
public void print() {
System.out.println("这是匿名内部类");
}
};
* 3、匿名内部类是一个对象,也相当于实现接口Interface1的无名子类
* */
Interface1 i = new Interface1() {
@Override
public void print() {
System.out.println("这是匿名内部类方式一");
}
}; //4、匿名内部类尾部记得加;
i.print();
System.out.println(i.getClass());
}
public void Method1(){
/*匿名内部类方式二
* 1、可以理解为:相当于类FatherClass的子类的实例对象
* 2、编译类型是FatherClass类
* 3、运行类型是: class p4.Anonymous$2 表示Anonymous编号为2的内部类
FatherClass() {
@Override
public void test() {
System.out.println("这是匿名内部类方式二");
}
};
* */
FatherClass father = new FatherClass() {
@Override
public void test() {
System.out.println("这是匿名内部类方式二");
}
};father.test();
System.out.println(father.getClass());
}
//测试
public static void main(String[] args) {
new Anonymous().Method();//匿名内部类方式一
new Anonymous().Method1();//匿名内部类方式二
}
}
输出:
这是匿名内部类方式一
class p4.Anonymous$1
这是匿名内部类方式二
class p4.Anonymous$2
2、匿名内部类的调用特点:
1、通过对象本身调用内部类的方法
new FatherClass() {
@Override
public void test() {
System.out.println("这是匿名内部类方式二");
}
}.test();
2、通过对象引用调用本身内部的方法
FatherClass father = new FatherClass() {
@Override
public void test() {
System.out.println("这是匿名内部类方式二");
}
};father.test();
3、匿名内部类的应用场景
1、当作实参直接传递
代码举栗:
public class Anonymous01 {
public static void main(String[] args) {
Kitchen kitchen = new Kitchen();
/**
* 1、匿名内部类只执行一次,适合作参数进行传递
* */
kitchen.rinseFood(new Soup(){
public void cooking(){
System.out.println("午餐吃阳澄湖大闸蟹");
}
public void stewSoup(){
System.out.println("加三鲜汤");
}
});
kitchen.rinseFood(new Soup() {
@Override
public void cooking() {
System.out.println("午餐吃糖醋排骨");
}
@Override
public void stewSoup() {
System.out.println("加排骨萝卜汤");
}
});
}
}
//烹饪接口
interface ICook{ void cooking();}
//煮汤接口
interface Soup extends ICook{ void stewSoup();}
//厨房类
class Kitchen {
//洗菜方法
public void rinseFood(Soup soup){
soup.cooking();
soup.stewSoup();
}
}
输出:
午餐吃阳澄湖大闸蟹
加三鲜汤
午餐吃糖醋排骨
加排骨萝卜汤
4、如何使用多态机制把局部内部类接到外部类使用
##### 1、使用接口接收
```
package p5;
public class Test {
public static void main(String[] args) {
/**
* 1、frock类型class p5.Frock; inner类型是class p5.Frock$1InnerH3
* 2、frock.h2()返回对象类型是其实是实现接口InnerH3类的对象类型,
* 属于外部类Frock的成员,所以不需要向下转型
* */
Frock frock = new Frock();
Inner inner = frock.h2();
inner.show();
System.out.println(frock.getClass());
System.out.println(inner.getClass());
}
}
//1、使用接口把内部类InnerH3接出来
interface Inner{ public void show();}
//使用子类把InnerH3接出来
//外部类Frock
class Frock {
int a1 = 20;
//局部内部类
public Inner h2(){
class InnerH3 implements Inner{
int a1 = 10;
public void show(){
System.out.println("------------------");
//内部类成员与外部类成员重名时,在内部类调用属性遵循就近原则
System.out.println("局部内部类-a1:"+a1);
//调用外部类成员名使用必须 外部类名.this.重名属性名,this.重名属性名都不行
System.out.println("外部类属性-a1:"+Frock.this.a1);
}
}
InnerH3 innerH3 = new InnerH3();
innerH3.show();
return innerH3;
}
}
输出:
------------------
局部内部类-a1:10
外部类属性-a1:20
------------------
局部内部类-a1:10
外部类属性-a1:20
class p5.Frock
class p5.Frock$1InnerH3
```
##### 2、使用抽象类接收
package p5;
public class Test1 {
public static void main(String[] args) {
/**分析:
* 1、frock1对象类型是class p5.Frock1,
* 而inner1类型是 class p5.Frock1$1InnerH3,所以需要向下转型
* 2、 frock1.h2()返回对象是抽象类的子类,转成抽象类类型Inner1时,所以需要向下转型
* */
Frock1 frock1 = new Frock1();
Inner1 inner1= (Inner1) frock1.h2();
inner1.show();
System.out.println(frock1.getClass());
System.out.println(inner1.getClass());
}
}
//1、使用接口把内部类InnerH3接出来
//interface Inner{ public void show();}
//2、使用抽象类把InnerH3接出来
abstract class Inner1{ //
/**第一步,建一个抽象类和抽象方法,
* 给h2()方法提供一个接受内部类对象
* */
public void show(){}
}
//外部类Frock
class Frock1 {
int a1 = 20;
//局部内部类
public Inner1 h2(){
/**
* 第二步,让内部类继承抽象类,
* 然后返回内部类对象,让抽象类接收
* */
class InnerH3 extends Inner1{
int a1 = 10;
public void show(){
System.out.println("------------------");
//内部类成员与外部类成员重名时,在内部类调用属性遵循就近原则
System.out.println("局部内部类-a1:"+a1);
//调用外部类成员名使用必须 外部类名.this.重名属性名,this.重名属性名都不行
System.out.println("外部类属性-a1:"+Frock1.this.a1);
}
}
InnerH3 innerH3 = new InnerH3();
innerH3.show();
return innerH3;
}
}
8.4、 成员内部类
1、成员内部类介绍:
1、顾名思义,就是定义在外部类的成员位置(除方法中外),没有static修饰,可以直接访问外部类的所有成员,包括私有属性!
2、它可以使用任何访问修饰符,因为它的地位属于成员而不是局部
3、如果成员内部类的成员与外部类的成员有重名的,那么在内部类调用内部类成员,直接调用;在内部类调用外部类重名成员时,使用 外部类名.this.重名成员名
格式长这样:
class OtherClass{
private String str="老黄牛"
class InnerClass{
public void show(){
System.out.println("向"+str+"学习")
}
}
}
代码举栗(成员内部类):
package p5;
public class Test01 {
public static void main(String[] args) {
//调用成员内部类方式一、
OtherClass otherClass = new OtherClass();
otherClass.new InnerClass().show();
//方式二、
otherClass.Method().show();
}
}
class OtherClass{
private String str="老黄牛";
private void PMethod(){
System.out.println("我是私有方法");
}
//成员内部类
class InnerClass{
public InnerClass show(){
//1、成员内部类访问外部类,直接访问
System.out.println("向"+str+"学习");
PMethod();
return null;
}
}
public InnerClass Method(){
//2、外部类访问成员内部类的成员,先创建内部类对象.成员
return new InnerClass();
}
}
2、如果内部成员类被私有化了,外部其他类还是想访问该私有成员类中的方法呢,怎么办呢?还是用接口接出来
代码举栗:
方式一、接口
package p5;
import javax.jws.Oneway;
public class Test01 {
public static void main(String[] args) {
//方式一、接口
OtherClass otherClass = new OtherClass();
I i = otherClass.PMethod();
i.show();
}
}
//方式一、接口
interface I{ public void show();}
//方式二、抽象类
//abstract class ABS{ public void show(){}}
class OtherClass{
private String str="老黄牛";
public InnerClass PMethod(){
return new InnerClass();
}
//成员内部类
private class InnerClass implements I{
public void show(){
//1、成员内部类访问外部类,直接访问
System.out.println("向"+str+"学习");
PMethod();
}
}
}
输出:
向老黄牛学习
-------------------------------------------------------------------------------
方式二、抽象类
package p5;
public class Test02 {
public static void main(String[] args) {
//方式二、抽象类
OtherClass01 otherClass01 = new OtherClass01();
ABS abs = (ABS)otherClass01.PMethod();
abs.show();
}
}
//方式二、抽象类
abstract class ABS{ public void show(){}}
//外部类
class OtherClass01{
private String str="老黄牛";
public InnerClass PMethod(){
return new InnerClass();
}
//成员内部类
private class InnerClass extends ABS{
public void show(){
//1、成员内部类访问外部类,直接访问
System.out.println("向"+str+"学习");
PMethod();
}
}
}
输出:
向老黄牛学习
3、如果成员内部类的成员与外部类的成员有重名的,那么调用在内部类调用外部类成员,直接调用; 在外部类调用内部类成员时,使用 外部类名.this.内部类成员名
8.5、 静态内部类
1、静态内部类的介绍
1、静态内部类 = 使用static修饰内部类
2、跟成员内部类其他的相同,唯一区别就是:静态内部类只能访问外部类的静态成员
2、静态内部类的使用方式:
package p5;
public class Test03 {
public static void main(String[] args) {
//方式二、
new OtherClass02().Method01();
//方式一
OtherClass02.Method01();
}
}
//外部类
class OtherClass02{
private static int a1 = 1;
private int a2 = 2;
static class InnerClass02{
public void Method(){
System.out.println("外部类属性a1:"+a1);
}
}
//在外部其他类,使用静态内部类的Method()方法
//方式一、使用静态方法直接调用静态方法
public static void Method01(){
new InnerClass02().Method();
}
//方式二、使用该方法返回一个静态内部类对象
public InnerClass02 Method02(){
return new InnerClass02();
}
}
3、当静态内部类成员与外部类成员出现重名时,在内部类调用内部类重名的成员时,直接调用; 在静态内部调用外部类静态重名成员,使用外部类名.重名成员名
#这里就不写代码举栗了
9、枚举
9.1、枚举的介绍
1、枚举的介绍:
1、枚举是一种特殊的类,用于表示一组常量,比如性别只有男和女,一天只有24小时等常识常量
2、使用关键字euum来定义,常量名使用大写,各常量之间使用,分割。 如eunum Sex{ MAN,WOWAN; }
2、枚举的实现方式:
1) 方式一、自定义枚举
public class Custom {
public static void main(String[] args) {
//类似调用静态属性调用,类名.属性名
System.out.println(Season.spring);
System.out.println(Season.summer);
System.out.println(Season.autumn);
System.out.println(Season.winter);
}
}
//自定义枚举: 季节类
class Season{
private String name;
private String description;
//把构造器私有化,不给外部new新的对象
private Season(String name, String description) {
this.name = name;
this.description = description;
}
//外部只能读取不能修改
public String getName() {
return name;
}
public String getDescription() {
return description;
}
//使用static + final是为了优化底层(不会触发类加载,但是这里new对象还是会类加载)
public static final Season spring = new Season("春季","温暖");
public static final Season summer = new Season("夏季","炎热");
public static final Season autumn = new Season("秋季","肃杀");
public static final Season winter = new Season("冬季","寒冷");
@Override
public String toString() {
return "季节:" + name + " 特点:"+ description;
}
}
自定义枚举注意点:
1、构造器私有化
2、本类内部使用 static+final 创建一组对象,对外暴露对象
3、只提供get方法,不提供set方法
2)方式二、使用enum关键字
package p5;
public class Custom {
public static void main(String[] args) {
//类似调用静态属性调用,类名.属性名
System.out.println(Season1.SPRING);
System.out.println(Season1.SUMMER);
System.out.println(Season1.AUTUMN);
System.out.println(Season1.WINTER);
}
}
//使用enum关键字实现枚举
enum Season1 {
//这个必须写到这个enum类的首行
//使用enum关键字,默认会让Season1继承Enumeration这个类
SPRING("春季", "温暖"),
SUMMER("夏季", "炎热"),
AUTUMN("秋季", "肃杀"),
WINTER("冬季", "寒冷");
private String name;
private String description;
private Season1(String name, String description) {
this.name = name;
this.description = description;
}
public String getName() {
return name;
}
public String getDescription() {
return description;
}
@Override
public String toString() {
return "季节:" + name + " 特点:"+ description;
}
}
小结(用enum关键字实现枚举注意细节)
1、枚举常量必须放在枚举类首行
2、当有多个枚举对象时,使用,隔开,用;结束
3、public static final Season1 枚举对象 = new Seson1("春天","温暖"); 等同于 SPRING("春天","温暖"),
9.2、枚举的常用方法
1、toString: Enum类已重写过,返回的是当前对象名(大写),子类可重写该方法,用于返回自定义的对象属性信息
2、name: 返回当前对象名(常量名),子欸不能重写
3、ordinal: 返回当前对象的位置编号,默认从0开始
4、values: 返回当前枚举类的所有常量
5、valueOf; 将字符串转成枚举对象,要求字符串必须为已存在的常量名,否则报异常
6、compareTo: 比较两个枚举常量的位置编号,
代码举栗:
package p5;
import com.sun.scenario.effect.impl.sw.sse.SSEBlend_SRC_OUTPeer;
public class Custom {
public static void main(String[] args) {
Season1 autumn = Season1.AUTUMN;
System.out.println(autumn);//这里已重写过
System.out.println(autumn.name());//返回大写的autumn对象名:AUTUMN
System.out.println(autumn.ordinal());//返回该对象的编号(理解下标也行),用于
System.out.println(Season1.values());//返回该枚举中所有对象,是一个数组类型,可迭代
Season1[] season1s = (Season1.values());
for (Season1 s:season1s){
System.out.println(s);
}
System.out.println(Season1.valueOf("SPRING"));//判断该枚举中是否有SPRING对象,有返回该对象信息,没有报异常
}
}
//使用enum关键字实现枚举
enum Season1 {
//这个必须写到这个enum类的首行
//使用enum关键字,默认会让Season1继承Enumeration这个类
SPRING("春季", "温暖"),
SUMMER("夏季", "炎热"),
AUTUMN("秋季", "肃杀"),
WINTER("冬季", "寒冷");
private String name;
private String description;
private Season1(String name, String description) {
this.name = name;
this.description = description;
}
public String getName() {
return name;
}
public String getDescription() {
return description;
}
@Override
public String toString() {
return "季节:" + name + " 特点:"+ description;
}
}
输出:
季节:秋季 特点:肃杀
AUTUMN
2
[Lp5.Season1;@14ae5a5
季节:春季 特点:温暖
季节:夏季 特点:炎热
季节:秋季 特点:肃杀
季节:冬季 特点:寒冷
季节:春季 特点:温暖
10、注解
1、注解的介绍:
1、注解也称为元数据,用于修饰解释包、类、方法、属性、构造器、局部变量等信息
2、和注释一相似之处在于它不影响代码逻辑,不同之处注解可以被编译货或运行,相当于嵌入代码中的补充信息
3、使用注解主要是为了标记过时功能、忽略警告信息等
10.1、Override
1、用于限定某个方法,常用于重写父类方法,该注解只能用于方法中
10.2、Deprecated
1、用于表示某个程序中的类、方法已过时
10.3、supresswarning
1、用于屏蔽编译器的警告信息
11、包装类与基本数据类型
11.1、包装类的介绍
1、在java中,有常见的8种基本数据类型,分别为byte、boolean、char、short、int、long、float、double,在工作中需要频繁使用它们进行各种操作。java设计者就为每个基本类型封装了一个类并提供常见的方法,大大提高了工作效率,而这些类就是包装类
2、基本类型 ---> 包装类
基本数据类型 | 包装类 |
---|---|
boolean | Boolean |
char | Character |
byte | Byte |
short | Short |
int | Integer |
long | Long |
float | Float |
double | Double |
2、装箱与拆箱
装箱: 基本类型 ————> 包装类型
拆箱: 包装类型 ————> 基本类型
3、装箱拆箱举栗:
package p5;
public class Packaging {
public static void main(String[] args) {
int i = 10;
//手动装箱(jdk1.5前)
Integer integer = new Integer(i);
Integer integer1 = Integer.valueOf(i);//手动装箱调用的其实是valueOf()方法
System.out.println(integer1.getClass());
System.out.println(integer.getClass()==integer1.getClass());
//手动拆箱
int i1 = integer.intValue();//拆箱调用的是intValue()方法
System.out.println(i1);
//自动装箱
short s = 10;
Short s1 = s;//底层调用的还是Short.ValueOf(s)
System.out.println(s1.getClass());
//自动拆箱
short s2 = s1; //底层调用的还是shortValue()进行拆箱
System.out.println(s2);
}
}
输出:
class java.lang.Integer
true
10
class java.lang.Short
10
11.2、小练习( 包装类)
1、以下输出结果是?
public static void main(String[] args) {
Integer i = new Integer(1);
Integer i1 = new Integer(1);
System.out.println(i==i1);
//false,new开辟了新的空间,所以不是同一个对象,故false
System.out.println(i.equals(i1));
//true,底成先判断两对象是否为同一类型对象,在判断两对象的值是否相等,相等返回true,否则false
Integer m = 1;
Integer n = 1;
System.out.println(n==m);
//true,底层会先判断该基本类型的值是否在-128~127之间,是就指向同一对象,否则new一个新对象
System.out.println(n.equals(m));
//true,底成先判断两对象是否为同一类型对象,在判断两对象的值是否相等,相等返回true,否则false
Integer x = 128;
Integer y = 128;
System.out.println(x==y);
//false,超过常量池范围-128~127之间,new新对象,不是同一对象,故false
System.out.println(x.equals(y));
//true,底成先判断两对象是否为同一类型对象,在判断两对象的值是否相等,相等返回true,否则false
}
2、下面输出的值是?
public static void main(String[] args){
Integer i = 127;
int i2 = 127;
System.out.println(i==i2);//true,只要比较时出现一个基本数据类型,比较的就是值大小
Integer i3 = 128;
int i4 = 128;
System.out.println(i3==i4);//true,只要比较时出现一个基本数据类型,比较的就是值大小
}
小结(包装类)
1、当基本数据类型与包装类==比较时,比较的是两对象的值
2、只要是new的对象,就不可以是同一对象
3、当两个包装类对象进行==比较时,如果对象值在-128~127之间,那就指向同一常量池对象