Java中的常用——Object类、Scanner类

1、API概述以及Object类的概述

  • API(Application Programming Interface) ——应用程序编程接口
  • Java API
    正如前面所看到的,一个Java 类包含许多方法。 而且, 在标准库中有几千个类, 方法数量更加惊人。要想记住所有的类和方法是一件不太不可能的事情。 因此,学会使用在线 API 文档十分重要,从中可以查阅到标准类库中的所有类和方法。Java提供给我们使用的类将底层的实现封装了起来,我们不需要关心这些类是如何实现的,只需要学习这些类如何使用。
  • Object类概述——类层次结构的根类
    Object类是java默认的提供的一个类,Object类是所有类的父类,也就是说任何一个类的定义的时候如果没有明确的继承一个父类的话,那么它就是Object的子类;

也就是说以下两种类的定义的最终效果是完全相同的:
class Person { }
class Person extends Object { }

1、使用Object类接收所有类的对象

public class MyTest1 {
    public static void main(String[] args) {
        fun(new Student());
        fun(new Person());
    }
    private static void fun(Object obj) {
        System.out.println(obj);
    }
}
class Student{ }
class Person{ }
//输出结果为:
org.westos.Mydemo.Student@1540e19d
org.westos.Mydemo.Person@677327b6

2、Object 类属于 java.lang 包,此包下的所有类在使用时无需手动导入,系统会在程序编译期间自动导入

2、Object类中的方法:

clone()
  • 该方法是保护方法,创建并返回了调用该方法的对象的副本,实现对象的浅克隆,只有实现了Cloneable接口才可以调用该方法 ,否则会抛出CloneNotSupportedException异常
  • 使用该方法的步骤:

1、要克隆的对象所在的类实现Cloneable接口(接口里面没有任何抽象方法,它的存在只是为了打一个标记,告诉JVM要进行克隆)
2、重写Object类中的方法(可以提高该方法的权限修饰符,j将原来的protected 改为 public),逻辑还是使用父类中的逻辑
3、在测试类里面创建该类的对象使用该方法,并定义一个该类的变量接收clone()方法的返回值

public class MyTest {
    public static void main(String[] args) throws CloneNotSupportedException {
       Singer s=new Singer("摇滚");
       Student st=new Student("张三",20,s);
       //克隆student对象
        Student st2=(Student)st.clone();
        st2.song.feature="说唱";
        System.out.println(st.song.feature);
        System.out.println(st2.song.feature);
    }
}
class Singer{
    String feature;
    public Singer(String feature){
        this.feature=feature;
    }
}
class Student implements Cloneable{
    String name;
    int age;
    Singer song;

    public Student(String name, int age, Singer song) {
        this.name = name;
        this.age = age;
        this.song = song;
    }
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}
运行结果为:
说唱
说唱
  • 浅克隆:前面我们在介绍这个方法的时候,我们说它是实现了对象的浅克隆,什么是浅克隆?
    通过上面的例子可以看出来,当我们将clone()返回值赋给新的对象st2时,通过 st2 这个对象再次给 Singer 类的成员变量 song 赋值的时候,同时也改变了st对象中的该成员变量

1、对象的浅克隆就是克隆一个对象的时候,如果被克隆的对象中维护了另外一个类的对象,这时候只是克隆另外一个对象的地址,而没有把另外一个对象也克隆一份。
2. 对象的浅克隆也不会调用到构造方法的。
3、对象的深克隆(后面讲): 采用IO流来实现 ,使用 ObjectOutputStream 将对象写入文件中,然后再用ObjectInputStream读取回来

getClass()
方法原型:public final Class getClass()
方法作用:返回此 Object 的运行时类,获取对象的真实类的全名称。

public class MyTest2 {
    public static void main(String[] args) {
        Object obj= new Object();
        Object obj2 = new Object();
        System.out.println(obj);
        System.out.println(obj2);
        System.out.println(obj==obj2);

        //获取该类的字节码文件对象
        Class aClass = obj.getClass();
        Class aClass1 = obj2.getClass();
        System.out.println(aClass==aClass1);
    }
}
输出结果:
java.lang.Object@1540e19d
java.lang.Object@677327b6
false
true

【 .java 文件加载进方法区的时候生成 .class,根据面对对象中万物皆对象的概念,把这个Object.class字节码也要看作一个对象,当这个文件一加载进内存,就会创建Object.class的对象,这个对象的类型是 Class ,来描述字节码文件类型,而一个类只有唯一的一个类型,也就只会有唯一的一个字节码文件,所以上面在判断两个对象的字节码文件类型时,结果是相同的】

toString()

源代码:
public String toString() { return getClass().getName() + "@" + Integer.toHexString(hashCode()); }

简单的来说就是返回一个地址值,该方法用得比较多,一般子类都有覆盖。你比如String类就会认为得到的地址值没有什么实际意义,它重写了这个方法,返回的是字符串本身。假如你以后打印一个对象名,它没有输出地址值,说明这个类重写父类Object 中的 toString()

public class MyTest3 {
    public static void main(String[] args) {
        Object obj = new Object();
        //获取该对象的16进制地址值,以字符串形式返回
        String s = obj.toString();
        System.out.println(s);
        
        Student student = new Student("zhangsan",23);
        System.out.println(student.toString());

        Student student2 = new Student("李四",24);
        System.out.println(student2);

        //子类对父类的方法实现,不满意那子类就可以重写父类方法

        Scanner scanner = new Scanner(System.in);
        System.out.println(scanner.toString());
        //假如 你以后打印一个对象名,他没有输出地址值,说明这个类重写父类Object 中的toString()
    }
}
输出结果为:
java.lang.Object@1540e19d
Student{name='zhangsan', age=23}
Student{name='李四', age=24}
java.util.Scanner[delimiters=\p{javaWhitespace}+][position=0][match valid=false][need input=false][source closed=false][skipped=false][group separator=\,][decimal separator=\.][positive prefix=][negative prefix=\Q-\E][positive suffix=][negative suffix=][NaN string=\Q�\E][infinity string=\Q∞\E]
//我们可以看到,打印一个对象名时,它就已经在默认的调用 toString() 方法了。我们发现Sccaner类也是重写了这个toString()方法,打印出它认为有意义的结果。

equals()
该方法是非常重要的一个方法,一般equals和双等号是不一样的,但是在Object类中两者是一样的。子类一般都要重写这个方法。
在这里插入图片描述
1、指示其他某个对象是否与此对象“相等”。
源代码:
public boolean equals(Object obj) {return (this == obj);}
2、默认情况下比较的是对象的引用是否相同
3、由于比较对象的引用没有意义,一般建议重写该方法。一般用于比较成员变量的值是否相等

public class Student extends Object {
    private String name;
    private int age;
    
    public Student() {
    }
    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }
    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
    @Override
    public boolean equals(Object o) {
    //当你在写一个方法时,你得考虑周全(健壮性),得考虑效率
    //来比较两个对象的成员变量值是否一样
        if (this == o) {
            return true;
        }
//那也就是是说向下转型时,得判断是不是我想要的类型
//instanceof(后面讲解)——判断一个引用(对象) 是不是该类型的一个引用
        /*if (!(obj instanceof Student)) {
            return false;
        }*/
        if (o==null||this.getClass() != o.getClass()) {
            return false;
        }
//那也就是是说向下转型时,得提前判断是不是我想要的类型
        Student student = (Student) o;
//你想要的比较的是两个字符串字面上的内容是否相同,你使用 == 号 比不出来
//String  extends Object String 类也认为。父类 equals()方法去比较两个字符串的地址值是否相同没有意义
//所以String 类也重写了equals()方法,去比较两个字符串的字面上的内容是否相同,而不去比较地址值
        return age == student.age && Objects.equals(this.name, student.name);
    }
}
测试类:
public class MyTest2 {
    public static void main(String[] args) {
        Student s1 = new Student("张三", 23);
        Student s2 = new Student("张三", 23);
        boolean b = s1.equals(s2);
        //父类Object中equals()的方法默认在比较两个对象的地址值是否相同,作为子类Student类,认为比较两个对象的地址值,是否相同意义不大。Student类认为,两个对象的成员变量值一模一样,就认为两个对象一样
        //Student类就可以重写equals()方法,来比较两个对象的成员变量值是否一样
        System.out.println(b);
    }
}
输出结果:true

hashCode()

public int hashCode()
1、该方法用于哈希查找,重写了equals方法一般都要重写hashCode方法。这个方法在一些具有哈希功能的Collection中用到。
2、一般必须满足obj1.equals(obj2)==true。可以推出obj1.hashCode()==obj2.hashCode(),但是hashCode相等不一定就满足equals。不过为了提高效率,应该尽量使上面两个条件接近等价。
3、返回该对象的哈希码值。默认情况下,该方法会根据对象的地址来计算。
4、不同对象的,hashCode()一般来说不会相同。 但是,同一个对象的hashCode()值肯定相同。
5、不是对象的实际地址值,可以理解为逻辑地址值

public class MyTest2 {
    public static void main(String[] args) {
        Person p=new Person("张三",20);
        System.out.println(p.hashCode());
    }
}
测试类:
public class Person {
    String name;
    int age;
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
    @Override
    public int hashCode() {
        return Objects.hash(name, age);
    }
}

3、Scanner的概述和构造方法原理

  • Scanner的概述: JDK5以后用于获取用户的键盘输入
  • Scanner的构造方法原理:
    Scanner(InputStream source)
    System类下有一个静态的字段:
    public static final InputStream in; 标准的输入流,对应着键盘录入。
    在这里插入图片描述

hasNextXxx() 录入输入并判断下一个是否是某种类型的元素,其中Xxx可以是Int,Double等。如果需要判断是否包含下一个字符串,则可以省略Xxx
nextXxx() 获取下一个输入项。Xxx的含义和上个方法中的Xxx相同
在这里插入图片描述

经过对输入结果不同的处理得到我们想要的结果,常用的有:
public int nextInt():获取一个int类型的值
public String nextLine():获取一个String类型的值
public String next():获取一个String类型的值,不会录入回车换行符

public class MyTest {
    public static void main(String[] args) {
        //录入字符串
        //先录入整数,在录入字符串,你会发现字符串录入不到
        Scanner s=new Scanner(System.in);
        int i=s.nextInt();
        System.out.println(i);

        String str=s.nextLine();
        System.out.println(str);
    }
}
输出结果为:
2
2

原因:你在输入一个整数之后键入Enter键,字符串s读取了这个字符串,解决方案就是:先获取一个数值后,在创建一个新的键盘录入对象获取字符串

public class MyTest {
    public static void main(String[] args) {
/*  Scanner(InputStream source),构造一个新的 Scanner,它生成的值是从指定的输入流扫描的。*/
        InputStream in = System.in;
/*public static final InputStream in“标准”输入流。此流已打开并准备提供输入数据。通常,此流对应于键盘输入*/
        Scanner scanner = new Scanner(in);
        //从键盘中可以录入多种类型的数据
        //int i = scanner.nextInt();
        //long l = scanner.nextLong();
        
        System.out.println("请输入一个整数");
        int i = scanner.nextInt();
        System.out.println(i);
        System.out.println("请录入一个字符串");
        scanner = new Scanner(in);
        //String s = scanner.nextLine(); //回车换行
        String s = scanner.next(); //不会录入回车换行符
        System.out.println(s);
    }
}
输出结果为:
请输入一个整数
12
12
请录入一个字符串
ert
ert
发布了13 篇原创文章 · 获赞 8 · 访问量 397

猜你喜欢

转载自blog.csdn.net/weixin_45082647/article/details/103748423