java基础(interface,访问控制,内部类,包装类,Object常用方法)

离散数学期末复习笔记【精华版】 文章目录前言一、????理逻辑1. 命题逻辑2. 等值演算3. 主合取范式、主析取范式4. 【题】推理证明5. 辖域、自由变元、约束变元二、????合1. 环和、环积,幂集,笛卡尔乘积三、 ????????关系1. 自反、对称、传递2&3. 合成运算,逆关系、闭包4. 哈斯图、上下界、偏序5. 等价关系、划分四、????1. 幺元(么元、单位元)、零元、逆元,半群、群、阿尔贝群、独异点、循环独异点2. 【题】由表判断3. 【题】证明五、????论1. 简单图、平凡图、多重图、子图、补图、出度、入度、 阅读详情

1.interface

引用数据类型:类、数组、接口

1.1 概述

接口是除了类和数组之外,另外一种引用数据类型

接口和类不同,类的内部封装了成员变量、构造方法和成员方法,而接口的内部主要就是封装了方法和静态常量。

接口的定义和类很类似,但是接口需要使用 interface 关键字来定义

接口最终也会被编译成.class文件,但一定要明确接口并不是类,而是另外一种引用数据类型

例如,

//使用interface关键字来定义接口
public interface Action {
	//接口中的静态常量
    public static final String OPS_MODE = "auto";
	
    //接口中的抽象方法
    public void start();
	
    //接口的抽象方法
    public void stop();

}

注意1, 定义类使用关键字class,定义接口使用关键字interface

注意2,接口中的属性都是公共的静态常量
注意:常量的名字一般需要全大写

注意3,接口中的方法都是抽象方法
注意:JDK8中,还允许在接口中编写静态方法和默认方法
注意:JDK9中,还允许在接口中编写私有方法

注意4,接口的中抽象方法,不需要使用abstract修饰符,因为接口中的方法默认就是抽象方法

在接口中,可把一些修饰符省去不写:

//使用interface关键字来定义接口
public interface Action {
	//接口中的静态常量
    String OPS_MODE = "auto";
	
    //接口中的抽象方法
    void start();
	
    //接口的抽象方法
    void stop();

}

接口里面的属性,默认就是public static final修饰的

接口里面的方法,默认就是public abstract修饰的

所以这些都可以省去不写的

含有静态方法和默认方法的接口:(JDK8)

public interface Action {
    public default void run1() {
    	// 执行语句
    }
    public static void run2() {
    	// 执行语句
    }
}

含有私有方法的接口:(JDK9)

public interface Action {
    private void run() {
    	// 执行语句
    }
}

注意,我们一般所使用的接口,大多数都只是含义抽象方法

1.2 接口实现

类和类之间的关系是继承,类和接口之间的关系是实现:一个类实现了一个或多个接口

接口和类不同,类可以实例化创建对象,而接口不能创建对象,只能让其他类来实现。

一个类实现了一个接口,那么该类可以称为这个接口的实现类。类实现一个接口 和 类继承一个父类 的效果类似,格式相仿,只是关键字不同,实现使用 implements 关键字,而继承使用的是extends关键字。

一个类实现了接口,那么就要实现接口中所有的抽象方法,否则这个类自己就必须声明为抽象类。

例如,实现一个接口

public interface Action {

    void run();
    void sayHello();

}
//类实现接口,没有实现接口中的抽象方法,那么这个类就必须声明为抽象类
abstract class Student implements Action{
    
}

public interface Action {

    void run();
    void sayHello();

}
//类实现接口,并且实现了接口中所有的抽象方法
class Student implements Action{
    public void run(){
        //...
    }
    
    public void sayHello(){
        //...
    }
}

例如,实现多个接口

public interface Action {

    void run();
    void sayHello();

}

public interface Mark{
    void star();
}

//类实现接口,并且实现了接口中所有的抽象方法
class Student implements Action, Mark{
    public void run(){
        //...
    }
    
    public void sayHello(){
        //...
    }
    
    public void star(){
        //...
    }
    
}

一个类实现了多个接口,那么就需要把这多个接口中的抽象想法全都实现

JavaAPI中的String类,也实现了多个接口:

可以看出,String类继承Object类的同时,又实现了三个接口

1.3 接口继承

java中,类和类之间是单继承,接口和接口之间是多继承

例如,

//实现该接口的类,将具有run的功能
public interface Runable {
    void run();
}
//实现该接口的类,将具有fly的功能
interface Flyable{
    void fly();
}

//实现该接口的类,将具有run的功能,fly的功能,以及Action接口独有的doSomething功能
interface Action extends Runable,Flyable{
    void doSomething();
}

//实现类,实现Action接口,就必须要实现Action及其父接口中的所有抽象方法
class Demo implements Action{

    @Override
    public void run() {
        
    }

    @Override
    public void fly() {

    }

    @Override
    public void doSomething() {

    }
}

1.4 多态

多态的前提是继承,必须要先有子父类关系才行,而类和接口之间的实现关系,其实也是继承的一种形式,所以在类和接口的实现关系中,也可以使用多态

接口的引用执行它的实现类对象:

public interface Action {
    void run();
}

class Student implements Action{

    @Override
    public void run() {
        
    }
}

class Teacher implements Action{

    @Override
    public void run() {
        
    }
}

class StudentTest{
    public static void main(String[] args) {
        //声明接口的引用
        Action a;
        
        //可以指向它任意一个实现类对象
        a = new Student();
        a = new Teacher();
      
    }
}


接口的引用调用方法,调用到的是实现类中重写的方法

class StudentTest{
    public static void main(String[] args) {
        
        Action a = new Student();;   
        //调用是到的方法是Student中重写(实现)的方法
        a.run();
    }
}

注意,抽象方法的实现,也算是一种方法的重写,形式、语法完全一致。

1.5 案例

public interface Action {
    void run();
}

interface Mark{
    void star();
}

class Student implements Action,Mark{

    @Override
    public void run() {
        System.out.println("student run...");
    }

    @Override
    public void star() {
        System.out.println("student star...");
    }
}

思考,下面代码是否正确?:

class StudentTest{
    public static void main(String[] args) {
		Action a = new Student();
        a.run();
        a.star();
    }
}

mian方法中,a.run()编译运行都是正确的,但是 a.star()方法的调用是编译错误的。

因为,在编译的时候,编译器会先检查引用a所属的类型(Action)中,是否存在当前要调用的方法(star),如果没有那么就直接编译报错。

那么在这种情况下,该如何修改代码,才能正确调用到star方法?

class StudentTest{
    public static void main(String[] args) {
		Action a = new Student();
        a.run();
        Mark m = (Mark)a;
        m.star();
    }
}

在这里,可以先做类型强制转换,把Action类型的引用a,转账转为Mark类型的引用m,然后使用引用m,就可以调用到Mark接口中的star方法,同时Student中对star进行了实现(重写),那么最后调用的是Student中的star方法。

思考,上面代码中,Action类型的引用a,为什么可以转换为Mark类型的引用m?注意,Action和Mark之间并没有任何关系

Action a = new Student();
Mark m = (Mark)a;

引用a,能否转账转为Mark类型,主要是看引用a,所指向的对象,是否实现了接口Mark,如果是的话,那么就可以转换成功。

同时,也可以是instanceof关键字,对引用a所指向的对象进行判断,是否属于Mark类型,如果是就说明该对象实现了Mark接口,属于Mark类型的,例如

Action a = new Student();
//返回true,则表示a指向的对象,也同时实现了Mark接口,属于Mark类型,那么就可以做强制转换
if(a instanceof Mark){
    Mark m = (Mark)a;
}

思考,如何让开发人员,一定能按照我们的预先设计好的方法,去编写代码?

把所有要实现的方法都放在接口里面,再让开发人员去实现接口

==思考,如果想要实现一个接口,但是不想重写里面的个别方法?

定义一个中间类,空实现接口中所有的类,然后再写个类去继承中间类,然后重写你想要的方法。

2 访问控制

对象中的属性和方法,是可以根据指定修饰符来进行访问控制的。具体控制的就是,这些属性和方法可以在什么地方被访问,以及在什么地方不能被访问。

2.1 概述

类中的属性和方法,可以使用以下四种修饰符进行访问控制:

public > protected > default > private

  • public,公共的,在所有地方都可以访问

  • protected,受保护的,当前类中、子类中,同一个包中其他类中可以访问

  • default,默认的,当前类中、同一个包中的子类中可以访问
    注意,default默认的,指的是空修饰符,并不是default这个关键字

    例如,String name; 在类中,这种情况就是默认的修饰符

  • private,私有的,当前类中可以访问

修饰符类中同包非子类同包子类不同包子类不同包非子类
publicYYYYY
protectedYYYYN
defaultYYYNN
privateYNNNN

2.2 案例

例如,

package com.briup.day09.demo;


public class AccessControl {

    public      String public_str    = "public_str";
    protected   String protected_str = "protected_str";
                String default_str   = "default_str";
    private     String private_str   = "private_str";


    //在当前类中访问
    public void test(){
        System.out.println(public_str);
        System.out.println(protected_str);
        System.out.println(default_str);
        System.out.println(private_str);
    }


}

class SamePackage{
    //在同包的非子类中访问
    public void test(){
        //需要先创建对象,然后再访问
        AccessControl ac = new AccessControl();
        System.out.println(ac.public_str);
        System.out.println(ac.protected_str);
        System.out.println(ac.default_str);

        //编译报错,无法访问
        //System.out.println(ac.private_str);
    }
}

class SamePackageSubClass extends AccessControl{
    //在同包的子类中访问
    public void test(){
        //继承后,可直接访问
        System.out.println(public_str);
        System.out.println(protected_str);
        System.out.println(default_str);

        //编译报错,无法访问
        //System.out.println(ac.private_str);
    }
}



在另一个包中,创建类进行访问测试:

package com.briup.day09.other;

import com.briup.day09.demo.AccessControl;


public class OtherPackage {
    //在不同包的非子类中访问
    public void test(){
        //需要先创建对象,然后再访问
        AccessControl ac = new AccessControl();
        System.out.println(ac.public_str);

        //编译报错,无法访问
        //System.out.println(ac.protected_str);
        //System.out.println(ac.default_str);
        //System.out.println(ac.private_str);
    }
}

class OtherPackageSubClass extends AccessControl{
    //在不同包的子类中访问
    public void test(){
        //继承后,可直接访问
        System.out.println(public_str);
        System.out.println(protected_str);

        //编译报错,无法访问
        //System.out.println(default_str);
        //System.out.println(ac.private_str);
    }
}

思考,正常情况下,编写一个类,都可以使用哪些权限控制修饰符?

正常编写的类,可以使用俩种权限控制修饰符:public和default

例如,

public class Person{}

class Student extends Person{}

但是,如果是内部类的话,则可以使用四种权限控制修饰符:

例如,

public class Test{
    private class A{}
    class B{}
    protected class C{}
    public class D{}
}

在Test类的内部,嵌套了四个内部类:A B C D,分别使用了private、default、protected、public进行了修饰

3 内部类

内部类,不是在一个java源文件中编写俩个平行的类,而是在一个类的内部再定义另外的一个类。

例如,这种情况是不是内部类,而是俩个独立的类

public class Test{
    
    
}

class A{
    
}

例如,这种情况是,是内部类,一个类内部嵌套了另一个类

//Test是外部类
public class Test{
    //A是Test类中的内部类
    public class A{
    
	}
    
}

内部类一共分为四种形式:

  • 成员内部类
  • 静态内部类
  • 局部内部类
  • 匿名内部类

注意,在A类中,嵌套声明了一个类B,以下都会将A类称为外部类,将B类称为内部类

class 外部类 {
    class 内部类{
    }
}

3.1 成员内部类

在类中,可以定义成员方法、成员变量,除此之外,还可以定义成员内部类

例如,

//外部类
public class MemberOuterClass{
    
    //外部类的属性
    private String name;
    private static int age;
    
    //外部类的方法
    public void run(){}
	public static void go(){}
	
    /* 成员内部类 声明开始 */
    public class MemberInnerClass{
        private String name;
        private int age;

        public void run(String name){}

    }
    /* 成员内部类 声明结束 */

}

注意,成员内部类中,【不能】编写静态的属性和方法

注意,当前这个代码,编译成功后,会生成俩个class文件,一个对应外部类,一个对应内部类

编译生成的俩个class文件的名字分别为:
MemberOuterClass.class
MemberOuterClass$MemberInnerClass.class

成员内部类和外部类的相互访问:

  1. 成员内部类访问外部的属性和方法
public class MemberOuterClass {
    //外部类的属性
    private String name;
    private static int age;

    //外部类的方法
    public void run(){}
    public static void go(){}

    /* 成员内部类 声明开始 */
    public class MemberInnerClass{
        private String name;
        private int age;

        public void run(String name){
            //访问当前run方法中的参数name
            System.out.println(name);
            //访问内部类自己的属性name
            System.out.println(this.name);

            //访问外部类的非静态属性
            System.out.println(MemberOuterClass.this.name);
            //访问外部类的静态属性
            System.out.println(MemberOuterClass.age);

            //访问外部类的非静态方法
            MemberOuterClass.this.run();
            //访问外部类的静态方法
            MemberOuterClass.go();

        }

    }
    /* 成员内部类 声明结束 */
}
  1. 外部类访问成员内部类的属性和方法
public class MemberOuterClass {
   
    //外部类的方法,访问成员内部类的属性和方法
    public void test(){
        //需要创建内部类对象,然后才可以访问
        MemberInnerClass t = new MemberInnerClass();
        System.out.println(t.name);
        System.out.println(t.age);
        t.run("tom");
    }

    /* 成员内部类 声明开始 */
    public class MemberInnerClass{
        private String name;
        private int age;

        public void run(String name){
            
        }

    }
    /* 成员内部类 声明结束 */
}

在其他类中使用这个内部类:

如果这个成员内部类不是private修饰的,那么在其他类中就可以访问到这个内部类

package com.briup.day09.demo;

import com.briup.day09.demo.MemberOuterClass.MemberInnerClass;


public class Test {

    public static void main(String[] args) {
        MemberOuterClass moc = new MemberOuterClass();

        MemberInnerClass mic = moc.new MemberInnerClass();

        mic.run("tom");

    }

}

在其他类中,使用这个非private修饰的成员内部类的时候,需要注意以下几点:

  1. 这个内部类需要import导入,并且是外部类.内部类的形式导入。
  2. 在创建对象的时候,需要先创建出外部类对象,然后使用外部类对象再创建内部类对象。
    形式为:外部类对象.new 内部类对象();

JavaAPI中的使用的成员内部类:

java.util.ArrayList类中,就定义了好几个成员内部类,并且还是private修饰的

思考,类的内部除了嵌套另一个类之外,是否还可以嵌套接口?

可以,不仅类中可以嵌套接口,接口的内部也可以嵌套其他接口。

例如,参考java.util.Map接口中的内部接口Entry

思考,什么情况下会使用内部类?

在对事物进行抽象的时候,若一个事物内部还包含其他事物,就可以考虑使用内部类这种结构。

例如,汽车(Car)中包含发动机(Engine) ,这时, Engine 类就可以考虑(非必须)使用内部类来描述,定义在Car类中的成员位置。

这样设计,既可以表示Car和Engine的紧密联系的程度,也可以在Engine类中很方便的使用到Car里面的属性和方法

例如,

public class Car { //外部类
    class Engine { //内部类
    }
}

例如,人(Person)中包含心脏(Heart),这时,Heart类可以考虑(非必须)使用内部类来描述,定义在Person类中的成员位置。

这样设计,既可以表示Person和Heart的紧密联系的程度,也可以在Heart类中很方便的使用到Person里面的属性和方法

例如,

public class Person { //外部类
    class Heart { //内部类
    }
}

注意,这是从程序中,类和类之间的关系和意义进行考虑而设计的,其实这里即使不使用内部类的结构,使用普通的俩个类也能完成功能,但是内部类的结构设计会加符合实际意义,也能够好的完成功能,因为内部类访问外部的属性和方法会更加容易。

3.2 静态内部类

静态内部类和成员内部类是类似的,只是这个内部类,多了static关键字进行修饰。

例如,

//外部类
public class StaticOuterClass{

    /* 静态内部类 声明开始 */
    public static class StaticInnerClass{	


    }
    /* 静态内部类 声明结束 */

}

注意,静态内部类中,【可以】编写静态的属性和方法,另外在四种内部类中,只有静态内部类可以编写静态属性和方法

编译生成的俩个class文件的名字分别为:
StaticOuterClass.class
StaticOuterClass$StaticInnerClass.class

静态内部类和外部类的相互访问:

  1. 静态内部类访问外部的属性和方法
public class StaticOuterClass {
    //外部类的属性
    private String name;
    private static int age;

    //外部类的方法
    public void run(){}
    public static void go(){}

    /* 静态内部类 声明开始 */
    public static class StaticInnerClass{
        private String name;
		private static int age;

        public void run(String name){

            //访问当前run方法中的参数name
            System.out.println(name);
            //访问内部类自己的属性name
            System.out.println(this.name);
            //访问内部类自己的静态属性age
            System.out.println(age);

            //静态内部类中,无法访问外部类的非静态属性和方法
            //System.out.println(StaticOuterClass.this.name);
            //StaticOuterClass.this.run();

            //访问外部类的静态属性和方法
            System.out.println(StaticOuterClass.age);
            StaticOuterClass.go();

        }

    }
    /* 静态内部类 声明结束 */

}

注意,在静态内部类中访问不了外部类中的非静态属性和方法

  1. 外部类访问静态内部类的属性和方法
public class StaticOuterClass {

    public void test(){
        //外部类中,访问静态类中的静态属性
        System.out.println(StaticInnerClass.age);

        //外部类中,访问静态内部类中的非静态属性和方法
        StaticInnerClass sic = new StaticInnerClass();
        System.out.println(sic.name);
        sic.run("tom");
    }

    /* 静态内部类 声明开始 */
    public static class StaticInnerClass{
        private String name;
        private static int age;
        
        public void run(String name){

        }

    }
    /* 静态内部类 声明结束 */

}

在其他类中使用这个内部类:

如果这个静态内部类不是private修饰的,那么在其他类中就可以访问到这个内部类

import com.briup.sync.StaticOuterClass.StaticInnerClass;

public class Test {

    public static void main(String[] args) {

        StaticInnerClass  sic = new StaticInnerClass();
        sic.run("tom");

    }

}

在其他类中,使用这个非private修饰的静态内部类的时候,需要注意以下几点:

  1. 这个内部类需要import导入,并且是外部类.内部类的形式导入。
  2. 在创建对象的时候,直接使用这个静态内部类的名字即可:new 静态内部类对象();,不再需要依赖外部类对象了。

JavaAPI中的使用的静态内部类:

java.lang.Integer类中,就定义了一个静态内部类,并且还是private修饰的

思考,观察Integer类中私有静态内部类IntegerCache,它的作用是什么?

Integer num1 = Integer.valueOf(127);
Integer num2 = Integer.valueOf(127);

System.out.println(num1 == num2); //输出结果为 true

Integer num3 = Integer.valueOf(128);
Integer num4 = Integer.valueOf(128);

System.out.println(num3 == num4);//输出结果为 false

注意,==表示要比较这个俩个对象的内存地址是否相等

3.3 局部内部类

局部内部类,是另一种形式的内部,在声明在外部类的方法中,相当于方法中的局部变量的位置,它的作用范围只是在当前方法中。

局部内部类是最不常用的一种内部类。

例如,

public class LocalOuterClass{
					
    public void sayHello(String name){

        /* 局部内部类 声明开始 */
        class LocalInnerClass{

        }
        /* 局部内部类 声明结束 */

    }
}

局部内部类和外部类的相互访问:

  1. 局部内部类访问外部的属性和方法
public class LocalOuterClass {
    //外部类的属性
    private String name;
    private static int age;

    //外部类的方法
    public void run(){}
    public static void go(){}

    public void sayHello(String name){

        /* 局部内部类 声明开始 */
        class LocalInnerClass{
            private String name;

            public void test(String name){

                //访问当前test方法中的参数name
                System.out.println(name);
                //访问内部类自己的属性name
                System.out.println(this.name);
                
                /*注意,sayHello方法的参数name,无法访问,因为实在没有办法表示了,换成其他名字后,就可以访问了,不要叫name就行*/
                
                //访问外部类的非静态属性
                System.out.println(LocalOuterClass.this.name);

                //访问外部类的非静态方法
                LocalOuterClass.this.run();

                //访问外部类的静态属性和方法
                System.out.println(LocalOuterClass.age);
                LocalOuterClass.go();

            }

        }
        /* 局部内部类 声明结束 */

    }

}
  1. 局部内部类中,访问当前方法中的变量,这个变量必须是final修饰的
public void sayHello(final String name){

    final int num = 1;


    /* 局部内部类 声明开始 */
    class LocalInnerClass{

        public void test(){

            System.out.println(name);
            System.out.println(num);

            //编译报错,final修饰的变量,只能赋值一次
            //name = "tom";
            //num = 2;

        }

    }
    /* 局部内部类 声明结束 */

}

在JDK1.8中,一个局部变量在局部内部类中进行方法了,那么这个局部变量自动变为final修饰

  1. 外部类访问局部内部类的属性和方法
public void sayHello(String name){

    /* 局部内部类 声明开始 */
    class LocalInnerClass{
        private int num;
        public void test(){

        }

    }
    /* 局部内部类 声明结束 */

	//创建局部内部类对象
    LocalInnerClass lic = new LocalInnerClass();
    //对象访问属性
    System.out.println(lic.num);
    //对象调用方法
    lic.test();

}

局部内部类,只能在当前声明的方法中进行使用。

3.4 匿名内部类

匿名内部类,是一种没有名字的内部类,它是内部类的一种简化写法。在之后的代码中,匿名内部类是使用最多的一种内部类。(很重要)

在普通的代码中,使用一个接口的步骤如下:

  • 声明一个类,去实现这个接口
  • 实现这个接口中的抽象方法(重写)
  • 在其他代码中,创建这个类的对象
  • 调用类中实现(重写)后的方法

其实,在这个过程中,我们的目的就是把接口中的抽象方法给实现(重写)了,最后再调用到这个实现后(重写)的方法。

那么,使用匿名内部类,就可以把这个过程给给简化了,让我们更加方法的调用到实现(重写)后的方法!

格式:

父类或者接口类型 变量名 = new 父类或者接口(){
    // 方法重写
    @Override
    public void method() {
    	// 执行语句
    }
};

//调用实现(重写)后的方法
变量名.method();

匿名内部类的俩种形式:

  • 利用一个父类,进行声明并创建匿名内部类对象,这个匿名内部类默认就是这个父类的子类型
  • 利用一个接口,进行声明并创建匿名内部类对象,这个匿名内部类默认就是这个接口的实现类

匿名内部类因为没有类名:

  • 匿名内部类必须依托于一个父类型或者一个接口
  • 匿名内部类在声明的同时,就必须创建出对象,否则后面就没法创建了
  • 匿名内部类中无法定义构造器

例如,利用父类型来声明并创建匿名内部类对象

public abstract class Animal {

    public abstract void run();

}

class Test{
    public static void main(String[] args) {
        Animal animal = new Animal(){
            @Override
            public void run() {
                System.out.println("匿名内部类中的默认实现");
            }
        };

        animal.run();

    }
}

注意,如果利用父类型声明这个匿名内部类,那么这个匿名内部类默认就是这个父类型的子类

例如,利用接口来声明并创建匿名内部类对象

public interface Action {
    void run();
}

class Test{
    public static void main(String[] args) {
        Action a = new Action(){

            @Override
            public void run() {
                System.out.println("匿名内部类中的默认实现");
            }
        };

        a.run();

    }
}

注意,如果利用接口声明这个匿名内部类,那么这个匿名内部类默认就是这个接口的实现类

思考,对比之前普通的方式,匿名内部类是不是在调用到重写方法的同时,简化了之前很多步骤?

案例:

//Algorithm 算法接口
public interface Algorithm{
    void sort(int[] arr);
} 

class Test{
    //使用指定算法,对数组arr进行排序
    public void sort(int[] arr,Algorithm alg){
        alg.sort(arr);
    }
}

public static void main(String[] args){
    Test t = new Test();
    
    int[] arr = {4,1,6,3,8,5,9};
    
    Algorithm alg = new Algorithm(){
        public void sort(int[] arr){
            //使用当前需要的排序算法
            //例如,这里简单的使用Arrays工具类中的排序方法
            java.util.Arrays.sort(arr);
        }
    };
    
    t.sort(arr,alg);
    
}


内部类的选择:

假设现在已经确定了要使用内部类,那么一般情况下,该如何选择?

  1. 考虑这个内部类,如果需要反复的进行多次使用(必须有名字)
    • 在这个内部类中,如果需要定义静态的属性和方法,选择使用静态内部类
    • 在这个内部类中,如果需要访问外部类的非静态属性和方法,选择使用成员内部类
  2. 考虑这个内部类,如果只需要使用一次(可以没有名字)
    • 选择使用匿名内部类
  3. 局部内部类,几乎不会使用

4 包装类

java中的八种基本数据类型,它们只能表示一些最简单的数字,这些数字最小的在内存中占8位,最大占64位。这些都是简单的数字,不是对象,所以也不能用来调用方法或者属性。

4.1 概述

针对这八种基本类型,JavaAPI又专门提供了对应的类类型,目的就是为了分别把这八种基本类型的数据,包装成对应的类类型,这时候就变成对象了,就可以调用方法了或者访问属性了。

基本类型包装类型
booleanjava.lang.Boolean
bytejava.lang.Byte
shortjava.lang.Short
intjava.lang.Integer
longjava.lang.Long
floatjava.lang.Float
doublejava.lang.Double
charjava.lang.Character

4.2 案例

在这些包装类型中,都定义相关的属性和方法,例如Integer中:

public static void main(String[] args) {

    int i = 1;
    //编译报错,因为i不是对象
    //i.toString();

    //int --> Integer
    //Integer o = new Integer(i);
    Integer o = Integer.valueOf(1);

    //Integer --> int
    int j = o.intValue();

    System.out.println(o.toString());

    System.out.println(Integer.MIN_VALUE);
    System.out.println(Integer.MAX_VALUE);


    //把100分别转为十进制、二进制、八进制、十六进制的字符串形式
    System.out.println(Integer.toString(100));
    System.out.println(Integer.toString(100,2));
    System.out.println(Integer.toString(100,8));
    System.out.println(Integer.toString(100,16));

    //把100转为二进制形式
    System.out.println(Integer.toBinaryString(100));

    //把字符串"100"转为int类型的100
    int num = Integer.parseInt("100");
    System.out.println(num);


}

4.3 自动装箱/拆箱

JDK1.5或以上,可以支持基本类型和包装类型之间的自动装箱、自动拆箱:

简化了基本类型和包装类型之间的转换,这里以int和Integer为例说明

//JKD1.5 之前
Integer o = new Integer(1);
Integer o = Integer.valueOf(1);

//JDK1.5 之后
//自动装箱,这里会自动把数字1包装成Integer类型的对象
Integer o = 1;


//JKD1.5 之前
Integer o = new Integer(1);
int i = o.intValue();


//JDK1.5 之后
Integer o = new Integer(1);
//自动拆箱,这里会自动把对象o拆箱为一个int类型的数字,并把数字赋值给int类型的变量i
int i = o;


其他的基本类型和包装类型之间的转换,与此类似

注意事项:

public class Test{
    
    public void test1(int i){}
	public void test2(Integer i){}
	public void test3(long i){}
	public void test4(Long i){}
    
    public static void main(String[] args){
        
        t.test1(1);//编译通过 int i = 1; 正常赋值
		t.test2(1);//编译通过 Integer i = 1; 自动装箱
		t.test3(1);//编译通过 long i = 1; 隐式类型转换
        
        //编译报错 
		//错误的代码:Long i = 1;
		//int和Long 之间没有任何关系
		t.test4(1);
        
        t.test4(1L);//编译通过 Long i = 1L; 自动装箱
        
    }
    
}

5 Object中常用方法

Object类是所有类的父类型,类中定义的方法,java中所有对象都可以调用

5.1 toString方法

该方法可以返回一个对象默认的字符串形式:

public class Object{
    public String toString() {
        return getClass().getName() + "@" + Integer.toHexString(hashCode());
    }
}

子类中可以对该方法进行重写:

public class Student{
    private String name;
    private int age;
    
    //get
    //set
    
    public String toString() {
        return "Student[name="+name+",age="+age+"]";
    } 
}

toString方法的调用:

public static void main(String[] args){
    Student stu = new Student();
    //这个俩个输出语句的效果是一样的
    System.out.println(stu);
    System.out.println(stu.toString());
}

注意,默认清下,println方法会调用这个对象的toString方法

注意,推荐使用第一种,因为当stu的值为null时,第二种输出方式会报错,空指针异常

5.2 getClass方法

该方法是非常重要的一种方法,它可以返回一个引用在运行时所指向的对象,具体类型是什么

该方法是native修饰的本地方法,不是java语言实现的。

public class Object{
    public final native Class<?> getClass();
}

子类中不能重写getClass,调用的一定是Object中的getClass方法:

public void test(Object obj){
    //obj可以接收任意类型的对象
    //getClass方法可以返回obj指向的对象具体是什么类型的
    //也就是该对象到底是使用哪个类创建出的对象
    System.out.println(obj.getClass());
}

5.3 equals方法

该方法可以比较俩个对象是否相等

public class Object{
    public boolean equals(Object obj) {
        return (this == obj);
    }
}

可以看出,Object中的equals方法,是直接使用的==号进行的比较,比较俩个对象的地址值是否相等

例如,

public static void main(String[] args){
    
    Student o1 = new Student();
    Student o2 = new Student();
    
    boolean f = o1.equals(o2);
    System.out.println(f);
}

子类中可以对该方法进行重写:

public class Student {
    private String name;
    private int age;

    public Student(){}

    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public boolean equals(Object obj) {
        //如果obj为null,直接返回false
        if(obj == null){
            return false;
        }
        //如果obj和this的地址值相等,直接返回true
        if(this == obj){
            return true;
        }
        //如果obj不属于Student类型的对象,直接返回false
        if(!(obj instanceof Student)){
            return false;
        }
        //obj属于Student类型的对象,做类型强制转换
        Student other = (Student) obj;
        //如果obj的name和age分别等于this的name和age,直接返回true
        if(this.name.equals(other.name) && this.age==other.age){
            return true;
        }
        //其他情况,直接返回false
        return false;
    }
}

class StudentTest{
    public static void main(String[] args) {
        Student s1 = new Student("tom",20);
        Student s2 = new Student("tom",20);

        System.out.println(s1 == s2);//输出false,因为俩对象的内存地址不同
        System.out.println(s1.equals(s2));//输出true,因为重写了equals的比较规则,name和age相等就算俩对象相等

    }
}

按照重写后的equals比较规则,只要俩个对象的name和age属性值都相等,那么就返回true,说明俩对象相等

对equals方法重写,一般需要注意以下几点:

  1. 自反性:对任意引用obj,obj.equals(obj)的返回值一定为true.
  2. 对称性:对于任何引用o1、o2,当且仅当o1.equals(o2)返回值为true时,o2.equals(o1)的返回值一定为true;
  3. 传递性:如果o1.equals(o2)为true, o2.equals(o3)为true,则o1.equals(o3)也一定为true
  4. 一致性:如果参与比较的对象没任何改变,则对象比较的结果也不应该有任何改变
  5. 非空性:任何非空的引用obj,obj.equals(null)的返回值一定为false

5.4 hashCode方法

该方法返回一个int值,该int值是JVM根据对象在内存的中的特征(地址值),通过hash算法计算出的一个结果。

Hash,一般翻译做“散列”,也可以音译为“哈希”,就是把任意长度的数据输入,通过散列算法,变换成固定长度的输出,该输出就是散列值。

一个任意长度的输入转为一个固定长度的输出,是一种压缩映射,也就是说,散列值的空间通常远小于输入的空间,不同的输入可能会散列成相同的输出,所以不可能从散列值来确定唯一的输入值。

所以,我们可以认为,Object中的hashCode方法默认返回的是对象的内存地址,但是实际上可能并不是。

public class Object{
    public native int hashCode();
}

对于俩个对象的hashCode值:

  • 相等的俩个对象,hashCode值一定相等
  • hashCode值相同,俩个对象有可能相等,也可能不同等
  • hashCode值不同,俩个对象一定不同

对象和它的hashCode值的关系,就相当于人和他的姓氏的关系:

  • 相等的俩个人,姓氏一样的相同
  • 姓氏相同的俩个人,可能是同一个人(相等),也可能不同的俩个人(不相等)
  • 姓氏不同的俩个人,一定是不同的俩个人

思考,hashCode在代码中有什么用?

现在有100个对象,突然又来了一个对象obj,那么怎么判断这个obj对象和之前的100个对象是否有相等的呢?

除了使用obj对象的equals方法和之前的100个对象比较100次之外,是否还有更好的方式?

高通Camx功能feature分析之十:高通NCS服务之注册和启动 本文介绍了高通NCS(非相机传感器)服务的注册与启动流程。NCS通过QMI接口访问陀螺仪等传感器,为相机EIS/AEC等功能提供辅助数据。文章详细解析了服务注册时的QueryCapabilites能力查询、RegisterService注册流程,以及通过StartNCSService启动服务线程的过程。重点包括:1)AF/EIS等节点通过NCSService创建传感器对象;2)注册时需校验传感器类型和接口;3)首次注册成功后会启动NCS服务线程;4)采样率变化时需重新配置会话。通过线程池管理实现传感器数据的 阅读详情

相关推荐

手把手教你用键盘在Ubuntu上给Lerobot机械臂采集HIL-SERL训练数据(附完整配置文件)

本文详细介绍了在Ubuntu系统中使用键盘控制Lerobot机械臂进行HIL-SERL训练数据采集的完整流程。从环境准备、机械臂校准到键盘遥操系统配置和数据采集优化,提供了实战指南和常见问题解决方案,帮助读者高效获取高质量训练数据,推动具身智能和强化学习应用的发展。

weixin_30733003的博客 477

java中的接口(Interface)

java中的接口(Interface)

qq_60030399的博客 1521

Nengo神经工程框架:脉冲神经网络的实时编译与硬件部署

脉冲神经网络(SNN)作为类脑计算的核心范式,正从生物模拟走向工程落地。其本质是用离散脉冲建模神经动力学,关键在于实现可预测、可复现的神经行为而非单纯拟合函数。Nengo基于神经工程学框架(NEF),将动态系统理论与硬件约束深度融合,通过解析式权重计算、确定性时间步长(dt)和多后端编译能力,支撑从CPU仿真到Loihi/FPGA的端到端部署。它不替代深度学习框架,而是提供面向神经形态芯片的‘神经编译器’能力,使LIF神经元参数、突触动力学与硬件时序严格对齐,显著提升实时性、能效比与物理可解释性。

weixin_32533659的博客 636

java中Interface和Object关系?

java中Interfaceh和Object关系?

BoomMan 1397

tcllib2.0 package - csv

tcl lib 的csv库

shin 859

VS2022错误列表高效处理:从复制到Excel表格的完整指南

本文详细介绍了在Visual Studio 2022中高效处理错误列表的实用技巧,重点讲解了如何将错误信息一键复制并粘贴到Excel表格中。通过基础操作、自定义视图、筛选功能及常见问题解决方案,帮助开发者将杂乱的编译错误整理成清晰、可排序、可筛选的数据表,极大提升了团队协作、错误分析和项目管理的效率。

weixin_28837817的博客 358

Java中interface是否继承Object类

首先我们从C++说起, c++可以多继承。也就是一个类型 --- class,可以继承自2个以上的父类型。多继承导致一个问题,很多人知道。例如,如果类型B,类型C均继承自类型A。然后类型D继承自类型B和C。那么构造D的实例的时候,由于要调用父类型的构造方法,最终会调用两次A的构造方法。结果类型D的实例有两套祖父的数据,也就是外公和爷爷长的一模一样,以后使用的时候很麻烦。每次D要和祖父打交道...

gengwei431的专栏 720

RV1106G3的fastboot调试

本文详细描述了在幸狐的Luckfox Pico Ultra硬件平台上,使用官方SDK进行系统优化和YOLOv5s模型部署的过程。首先,硬件板卡使用幸狐的SDK进行EMMC非Fastboot配置时功能正常,但Fastboot配置编译失败,通过修改设备树中的ramdisk大小解决了编译问题,但运行时仍报错。幸狐提供的Fastboot烧录文件可正常运行,表明硬件支持Fastboot。随后,使用官方SDK版本rv1106_rv1103_240813进行编译和调试,发现EMMC Fastboot启动失败,通过修改U-

fzktongyong的博客 2354

Java四种访问权限

一、访问权限简介访问权限控制: 指的是本类及本类内部的成员(成员变量、成员方法、内部类)对其他类的可见性,即这些内容是否允许其他类访问。Java 中一共有四种访问权限控制,其权限控制的大小情况是这样的:public > protected > default(包访问权限) > private public:Java语言中访问限制最宽的修饰符,一般称之为“公共的”。被其修饰的类、属...

weixin_34128411的博客 2490

Android AudioFlinger(一)——初识AndroidAudio Flinger

AudioFlinger 是 Android 系统中的音频中间层(audio HAL, Audio Hardware Abstraction Layer)的一部分,负责管理音频的混音、播放和音量控制等功能。它充当 Android 应用程序和音频硬件之间的桥梁。

hirezy 1663

MobaXterm隧道配置详解:为PyCharm远程开发打通‘最后一公里’

本文详细解析了如何利用MobaXterm配置SSH隧道,实现PyCharm远程开发的高效连接。通过本地端口转发技术,开发者可以安全访问内网服务器,特别适用于需要通过跳板机的复杂网络环境。文章涵盖从基础配置到企业级运维的全套解决方案,包括性能优化、安全加固等实用技巧。

weixin_30566063的博客 502

Java面向对象知识点总结04---接口 内部类

接口 内部类 lambda表达式实现接口 invoke

Aa102365478的博客 653

超临界二氧化碳再热再压缩布雷顿循环建模与先进控制

超临界二氧化碳布雷顿循环建模与先进控制研究 本文研究了超临界二氧化碳再热再压缩布雷顿循环系统的建模与控制。通过MATLAB/Simscape构建了包含压缩机、透平、回热器等关键组件的动态模型,并设计了基于模型预测控制(MPC)和自抗扰控制(ADRC)的多层控制策略。系统采用转速控制的压缩机、阀门开度控制的透平,以及可变热源加热器,实现了全动态分析。研究结果表明,MPC与ADRC混合控制方案相较于传统PID控制,功率超调降低至0.9%,效率波动控制在±0.08%,扰动恢复时间缩短至12秒。

AI的内部世界的博客 340

JAVA初步学习——第七章 静态、抽象、内部类

java的初级学习

qq_56078818的博客 1023

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版

Part-E1-SDIO-Specification-Ver4.00-Final-120220.pdf:最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版,包括SDIO 接口的外设,SDIO 接口官方协议等。

03 JavaSE-- 访问控制权限、抽象类/方法、interface、内部类、Object 类

03 JavaSE-- 访问控制权限、抽象类/方法、interface、内部类、Object 类

m0_46671240的博客 397

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

Java基础(二)——面向对象和类

先从简化的Java内存模型开始 栈区 基本数据类型的存储 引用数据类型的存储 堆区 方法区 面向对象要点(没对象的好好学、有对象的好好看) 类基础 方法中的不定长参数 这就是this? 返回一个this试试? this的特殊用法 看完之后就想静静的静态关键字static static与JavaBean 单例模式 什么是单例模式 单例模式的实现步骤 举例 内存分析 构造块和静态代码块 终于到final了 访问控制 封装 继承 继承的几大特点 老汉的遗产并不是全给娃娃的噢 子类如何使用父类的构造方法? 方法重写

荆州拉人去编程 4253

Java基础-类-接口interface-package-import.

一 Java通过关键字extends来实现集成 二 继承中的构造方法super 三 Package语句 Import语句 五 访问控制符修饰成员 六 Final关键字 七 抽象类 八 接口interface

jk823394954的专栏 907

【java基础-2】类Class和接口Interface

如果是引用类型,final只保证这个引用所引用的地址不会改变,即一直引用同一个对象,但这个对象完全可以发生改变。java用new来新建对象生成一个引用实例,引用变量表示地址,其指向堆中的对象。成员变量定义在类中的变量,可以不进行初始化,Java会自动进行初始化,如果是引用类型默认初始化为null,如果是基本类型例如int则会默认初始化为0;局部变量定义在方法中的变量,必须要进行初始化,否则不能通过编译。抽象类定义了对象是什么,是对根源的抽象;==》常用模板方法。

午后阳光 4030

Java基础[六]:封装

Java基础[六]:封装

太阳与星辰的博客 1228

Java基础语法

数组 数组的创建 int[] arr1; int[] arr2 = {}; // 空数组 int arr3[] = {}; // 空数组与上面完全等价, 但推荐上面那种 // 定义的时候指定数组元素 int[] arr4 = new int[] {1, 2, 3, 4}; // 可以省略数组长度 int[] arr5 = {1, 2, 3, 4}; // 是上面的简化写法(语法糖) // 定义...

CoderZk的博客 3906

java中接口interface和private私有内部类怎样一块配合着用?

3.接口interface和private内部类协同工作【新手可忽略不影响继续学习】马克-to-win:由于是private内部类,外面无法访问甚至无法看到你编的源代码(如果在不同的包中),非常安全。外界只能调用接口中的方法。下例中访问不了Core,甚至你不知道有Core的存在。给你的就是外部的接口,供你使用。马克-to-win:我们一直没讲class 如何能private, 这里内部类时,就可以...

mark_to_win的专栏 1029

常用类(1.内部类)

常用类可分为10种 1.内部类 内部类分为 :静态内部类,成员内部类 ,局部内部类 ,匿名内部类 静态内部类 静态内部类定义在类中,任何方法外,用static定义。 静态内部类只能访问外部类的静态成员。 生成(new)一个静态内部类不需要外部类成员:这是静态内部类和成员内部类的区别。静态内部类的对象可以直接生成: Outer.Inner in=new Outer.Inner();而不需要通过生成外部类对象来生成。这样实际上使静态内部类成为了一个顶级类。可以定义私有静态内部类。 生成(.

weixin_64145253的博客 747

JAVA内部类

成员内部类 分类: 1.成员内部类 2.局部内部类(包含匿名内部类) 注意: 1.内部类可以直接访问外部类,外部类需要通过内部类对象来访问内部类。 外部类访问内部类: 1.间接:通过外部类对象,调用外部类的方法,在外部类的方法里面间接使用内部类 2.直接:按照公式 外.内 ——如Body.Heart heart=new Body().new Heart(); heart.beat(); ...

qq_41870790的博客 176

简单理解 Java内部类

内部类 在Java中,可以将一个类定义在另一个类里面或者一个方法里面,这样的类称为内部类。广泛意义上的内部类一般来说包括这三种:成员内部类、局部内部类、匿名内部类。 三种内部类定义及使用如下: public class Outter { //成员内部类,定义在类内部的类 class UserInner { void user() { System.out.println("调用了成员内部类的方法"); } } //

Foo 392

Java类、接口、方法、变量修饰符总结

Java修饰符 修饰符很多,可以分为访问控制修饰符和非访问控制修饰符。(以下在JDK1.8所测) 有 public、private、protected、缺省、static、final、synchronized、abstract… ①访问控制修饰符 修饰符 说明 public 对所以累可见。可使用在:类、接口、方法、变量。 private 在同一个类可见。可使用在:方法、变量。...

不再更新,新博客 chgl16.space 1577

我的JAVA学习 基础(4)

十三 控制访问权限修饰词      private       修饰属性 属性只能在当前类中被调用                      修饰方法 方法也只能在本类中被调用        可以修饰内部类      default       修饰属性 在本类可以使用,在同一包下可以被使用                    修饰方法 一样      protected     修饰属性...

Leo_mmm的博客 224

你真的懂interface default吗?一场关于访问控制的灵魂拷问

掌握接口默认方法访问的正确方式,深入解析Java 8+中default方法的适用场景与访问控制机制。涵盖多继承冲突解决、接口升级兼容性优势及实际应用技巧,助你写出更灵活的代码,值得收藏。

FastDebug的博客 497
上一篇: 创建子类对象的顺序
下一篇: java基础(集合)
平平无奇的编码小天才
博客等级 码龄6年 15粉丝 39原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值