JavaSE:native,final,Object,抽象类,java.lang.Conmparable

一、关键字:native

1.native:本地的,原生的
2.作用:修饰方法
3.使用它修饰的方法我们在java原文件中看不到它的方法体
4.修饰后的方法有什么不用

不是java语言编写的,而是c语言或者c++编写的,由c编写的代码最后编译为.dll文件,由java代码调用。当这部分方法在运行时他会在JVM的本地方法栈中开辟空间

5.Java的内存划分

(1)方法区

(2)堆

(3)栈:Java虚拟机栈:运行:Java代码实现的方法

本地方法栈:运行native系列的c方法

6.如何使用native方法

(1)把他当成Java代码一样区调用即可

(2)如果子类需要也可以用Java代码进行重写

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

        MyClass my = new MyClass();
        System.out.println(my.hashCode());
    }
}
//手动继承Object类
class MyClass extends Object{
    @Override
    public int hashCode() {
        return 1;
    }
}

二、关键字 final

1.final:最终的,终结的
2.作用:

可以修饰类、变量、方法

3.修饰类:

【其他修饰符】 final class 类{

}

加final修饰的类就是不能被继承的类

例如:String、Math、System等

4.修饰方法

【修饰符】class类{

【其他修饰符】 final 返回值类型 方法名(【形参列表】){

}

【其他修饰符】native final 返回值类型 方法名(【形参列表】);

}

这样的方法,子类不能重写。但是可以被子类继承。

5.修饰变量

final 数据类型 变量 = 值;

(1)这样的变量的值不能修改

(2),final修饰的变量用大写,表示一个常量。

(3)必须保证final的成员变量,还有初始化的代码(值)。

public class TestFinal {
    public static void main(String[] args) {
        Student stu = new Student();
        stu.eat();//继承了

       final int a = 10;
//       a = 20;//不能修改

//        Chinese.COUNTRY = "中华人民共和国";//不能修改

        System.out.println(Math.PI);
    }
}
final class  TaiJian{

}
/*
class Sub extends TaiJian{

}*/
class Person{
    public final void eat(){
        System.out.println("吃东西");
    }
}
class Student extends Person{
    //不能重写eat()方法
/*    public final void eat(){
        System.out.println("吃好东西");
    }*/
}

class Chinese{
    static final String COUNTRY = "中国";//没有set方法
    final int MAX_AGE = 150;//没有set方法

    public static String getCOUNTRY() {
        return COUNTRY;
    }

    public int getMAX_AGE() {
        return MAX_AGE;
    }
}

//必须保证final的成员变量,还有初始化的代码(值)
class MyClass{
    final int a = 10;//可以是显式赋值
    final int b;
    {
        b = 20;//可以是代码块赋值
    }
    final int c;

    //可以是每一个构造器中赋值
    public MyClass(){
        c = 30;
    }
    public MyClass( int c) {
        this.c = c;
    }
}

三、根父类:Object

1.Object类在java.lang包
2.Object类时所有类的跟父类

API:Application Programming Interface 应用程序编程接口,俗称:帮助文档,开发基本说明书。

(1)所有类都直接或间接的继承了Object,或者说,如果一个类没有明确的写它的父类是谁,那么它的父类就是Object
(2)Object类中的方法,在所有类中都继承了,包括数组类型,因为数组类型也是引用数据类型。
(3)Object类型的变量可以接受任意类型的对象,换句话说,Object类型的数组可以装任意类型的对象,
Object类型的形参,可以接受任意类型对象作为实参。

但是有一点要注意:
Object[]的数组不能赋值为其他数组,只能赋值new Object[长度];

3.Object类的方法

(1)public String toString();

作用:返回该对象的字符串表示。

①结果应是一个简明但易于读懂的信息表达式。建议所有子类都重写此方法。

②如果没有重写,Object 类的 toString 方法返回一个字符串,该字符串由类名(对象是该类的一个实例)、at 标记符“@”和此对象哈希码的无符号十六进制表示组成。

(2)public final Class<?> getClass()

作用:获取一个对象的运行时类型

(3)protected void finalize() throws Throwable
(4)public boolean equals(Object obj)

指示其他某个对象是否与此对象“相等”。

①== : 如果是两个对象比较,那么表示比较的是他们的内存首地址,
如果返回true,说明它们就是“同一个”对象
②equals:
如果子类重写了equals方法,那么一般用于比较对象的内容。
如果子类没有重写,那么equals的效果和
是一样的

手动重写equals方法:

自反性: x.equals(x)必须返回true
对称性: x.equals(y)返回true,那么y.equals(x)必须返回true
传递性: x.equals(y)返回true,y.equals(z)返回true,那么x.equals(z)必须返回true
一致性: 只要在程序运行期间,参与equals比较的成员变量的值没有修改过,那么从头到尾x.equals(y)的结果是一致的。
任何非空对象与null比较都是false:x.equals(null)一定是false。 x一定是非空,因为如果x为null,就报NullPointerException空指针异常了。

public class TestObjectMethod4 {
    public static void main(String[] args) {
        String str1 = "hello";//常量池中,在方法区
        String str2 = "hello";
        System.out.println(str1 == str2);//true

        String str3 = new String("hello");//在堆
        System.out.println(str1 == str3);//false

        System.out.println("------------------------------");
        System.out.println(str1.equals(str2));//true
        System.out.println(str1.equals(str3));//true

        System.out.println("------------------------------");
        Circle c1 = new Circle(1);
        Circle c2 = new Circle(1);
        System.out.println(c1 == c2);//false
        System.out.println(c1.equals(c2));//false or true
    }
}

class Circle{
    private double radius;

    public Circle(double radius) {
        this.radius = radius;
    }

    public double getRadius() {
        return radius;
    }

    public void setRadius(double radius) {
        this.radius = radius;
    }

    @Override
    public String toString() {
        return "Circle{" +
                "radius=" + radius +
                '}';
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true; //当前对象(equals方法的.前面的对象)和equals()中对象,如果==相等,说明是自己与自己比较,肯定是true

        if (o == null || getClass() != o.getClass()) return false;
        //o为null,当前对象也不为空,因为当前对象为空的话,就进不来方法,就报NullPointerException空指针异常了,肯定false
        //||短路或,如果它判断右边的表达式了,说明o不为空
        //两个都不为空的对象, this.getClass() != o.getClass() 说明它俩的运行时类型不一致,不是同一个类型的对象,肯定false

        Circle circle = (Circle) o; //向下转型  安全,因为如果o不是Circle的对象,那么 上面的if就返回false,结束了
        return Double.compare(circle.radius, radius) == 0; //比较compare,circle的半径和this.radius,是否相等

        //这里为啥不  circle.radius == this.radius  因为double类型是不精确的,用==比较误差比较大
        //Double.compare(circle.radius, radius)是比较两个double的二进制值,更准确一点
    }

    @Override
    public int hashCode() {
        return Objects.hash(radius);
    }
}
(5)public int hashCode():

作用:返回该对象的哈希码值。支持此方法是为了提高哈希表(例如 java.util.Hashtable 提供的哈希表)的性能。
特点:
理想状况下,两个不同的对象的hashCode值是不同的,即hashCode是唯一的。
实际中,可能存在两个不同的对象的hashCode值是相同。

hashCode 的常规协定是:
①如果两个对象通过equals返回true,那么一定要保证这两个对象的hashCode值是一样的。
②如果两个对象的hashCode值是不同的,那么这两个对象调用equals一定是返回false。
③如果两个对象的hashCode值是相同的,那么这个两个对象调用equals可能为true,也可能为false

注意:equals和hashCode方法请一起重写,不要只重写一个,而且选择的成员变量要一致。

public class TestObjectMethod5 {
    public static void main(String[] args) {
        System.out.println("Aa".hashCode());//2112
        System.out.println("BB".hashCode());//2112
        System.out.println("Aa".equals("BB"));//false

        System.out.println("hello".hashCode());//99162322
        System.out.println(new String("hello").hashCode());//99162322
        System.out.println("hello".equals(new String("hello")));//true
    }
}

class Employee{
    private String name;
    private double salary;

    public Employee(String name, double salary) {
        this.name = name;
        this.salary = salary;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public double getSalary() {
        return salary;
    }

    public void setSalary(double salary) {
        this.salary = salary;
    }

    //以下重写是错误的,equals的成员变量选择和hashCode的成员变量选择不一致,是错误的。
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Employee employee = (Employee) o;
        return Double.compare(employee.salary, salary) == 0 &&
                Objects.equals(name, employee.name);
    }

    @Override
    public int hashCode() {
        return Objects.hash(salary);
    }
}

四、抽象类

1、什么情况下会用到抽象类
(1)当父类需要表明他的子类们应该具备什么样的功能(方法),但是在父类中又无法给出具体的实现,例如:图形类Graphic,觉得他的子类们应该具备getArea求面积,getPremeter()求周长,但是在父类中又无法给出合理的具体实现,那么在父类中把这样的方法声明为抽象的方法,一个类包含抽象方法,这个类就应该是抽象类。
(2)当父类仅仅用于表示一个抽象的概念,不希望使用者直接创建它的对象,而是在使用者去创建它更具体的子类的对象,那么这样的父类,虽然没有抽象方法,但是也会被设计为抽象类。

2、如何声明抽象类
抽象类的声明格式:
【修饰符】 abstract class 类名 【extends 父类】 【implements 接口们】{
}

3、抽象类的特点
(1)不能实例化(不能直接创建对象)
(2)如果一个类包含抽象方法,那么这个类必须是抽象类
(3)当然一个抽象类,可以没有抽象方法
(4)抽象类就是用来被继承的,子类继承抽象父类,那么一定要实现(重写)父类的抽象方法,否则这个子类也得是抽象类。
(5)抽象类可以与子类的对象之间构成多态引用。
(6)抽象类可以和普通类一样,具有属性、构造器、代码块、非抽象方法(静态的、非静态)、内部类等所有的成员。

五、修饰符

1.权限修饰符:public protected 缺省 private
2.static 静态,,可以共享的类型.调用的
3.final 最终,类:不能被继承,方法:不能被子类重写,可以被继承 ,变量:表示常量
  1. native 只能修饰方法,表示这个方法不是java语言实现的,但是可以调用
  2. abstract 抽象
  3. public 修饰类、成员变量、成员方法、构造器

    protected 修饰成员变量 成员方法、构造器

    缺省 修饰类、成员变量、成员方法、构造器

    private 修饰成员变量、成员方法、构造器

    static 修饰成员变量、成员方法、代码块

    final:修饰类、成员变量、成员方法、局部变量

    native 修饰成员方法

    abstract 修饰类、成员方法

    7.类:

    final和abstrace不能一起,因为final是不能被继承,abstract就是用来被继承的

    8成员变量

    权限修饰符四选一,同时可以static,又是final

    9.成员方法

    (1)static和final可以一起

    (2)static和abstarct不能一起

    (3)static和native可以

    (4)native和abstract不能一起

    它俩在Java中都没有方法体,但是它们没有方法体意义不同。

    native表示方法体在C语言中;
    abstract表示方法体在子类实现。

    (5)private和abstract 不能一起
    因为私有的不能被重写
    (6)final 和abstract 不能一起
    因为final不能被重写

    六、接口

(1)子类在继承父类,又实现接口时方法一样
①:默认情况下:父类优先原则
②:完全重写
③:选择保留接口:接口名.super.默认方法名

父类:亲生父亲
接口:干爹

(2)子类在实现多个接口时,
解决方案:
①选择其一: 接口名.super.默认方法名
②完全重写:

2.语法格式:

【权限修饰符】 interface 接口名{
}
这里把class换成了interface

  1. 实现一个接口
    【修饰符】 class 类名 implements 接口们{

}接口们表示可以是多个接口,多个接口之间使用,分割

4.接口的特点

(1)接口是不能直接new对象
(2)接口是用来被实现的,实现类实现接口时,必须重写/实现接口的所有抽象方法,否则这个实现类本身就必须是一个抽象类
(3)类实现接口支持多实现
(4)接口与实现类的对象之间也是多态引用

5、接口的成员

(1)没有构造器,代码块
(2)它如果要声明成员变量,只能声明public static final的成员变量,即公共的静态的常量。
其中public static final可以省略。

(3)接口中的成员方法
①在JDK1.8之前,只能是public abstract的抽象方法。
其中public abstract可以省略。

②JDK1.8增加了两种方法:
静态方法:public static 的静态方法,但是static是不能省略的,public可以省略。
默认方法:public default 的默认方法,其中default不能省略。

为什么增加静态方法的语法?
因为,之前的时候,接口中只能有抽象方法,那么在设计API的时候,很多关于该接口的工具类,就需要单独在声明一个类,
虽然这个工具类中全部都是静态方法,也不需要创建接口的对象,但是还必须单独声明一个类。
例如:Collection接口与Collections工具类
Path接口与Paths工具类

导致类型的数量增加,维护成本增加了。

为什么增加默认方法的语法呢?
①我们JDK已经发展了很多年了, 针对之前的接口,需要增加一个方法,如果按照之前的要求,只能增加抽象方法。
如果一个老版的接口增加了一个抽象方法,那么意味着原来实现了这个接口所有实现类全部都要修改,增加一个抽象方法的实现。
所以,增加了默认方法。
②我们发现很多接口的实现类,对于某个抽象方法的实现是一样,那么这样的抽象方法的实现,就可以在接口中声明为默认方法。

如何调用接口的静态方法?
接口名.静态方法

如何调用接口的默认方法?
使用对象调用。
只能用实现类的对象进行调用。

③JDK1.9之后,增加了私有方法

五小结

1、类与类:继承extends,单继承
2、类与接口:实现implements,多实现
3、接口与接口:继承extends ,多继承

(二)继承与实现的区别
继承和实现相似但是不同。
继承:除了构造器,其他都会继承过来。
实现:静态方法不会“传递”到实现类中,其他的抽象方法、默认方法等会“传递”到实现类中。

(三)
1、子类中想要访问父类的成员变量(可见),如果同名,需要区别的话
super.成员变量

2、子类中想要访问父类的成员方法(可见),如果重写,需要区别的话
super.成员方法

3、实现类中想要访问父接口的成员变量,如果同名,需要区别的话
接口名.成员变量

4、实现类中想要访问父接口的默认方法,如果重写,需要区别的话
接口名.super.默认方法

5、实现类中想要访问父接口的静态方法,
接口名.静态方法

六、经典接口

1、java.lang.Comparable接口
这个接口是两个对象比较大小的标准规范。
它有一个抽象方法:int compareTo(Object o)
规定: .前面的对象(即this) 大于 ()中的对象(即o对象) 返回正整数
规定: .前面的对象(即this) 小于 ()中的对象(即o对象) 返回负整数
规定: .前面的对象(即this) 等于 ()中的对象(即o对象) 返回0

举例:
需求:编写一个数组工具类MyArraysTools,里面包含一个方法,可以给任意的对象数组实现从小到大排序
public static void sort(Object[] arr)

public class TestComparable {
    public static void main(String[] args) {
        Student[] students = new Student[3];
        students[0] = new Student("zhangsan",25,89);
        students[1] = new Student("lisi",25,89);
        students[2] = new Student("wangwu",25,89);

        System.out.println("排序之前:");
        for (int i = 0; i < students.length; i++) {
            System.out.println(students[i]);
        }

        //排序
        MyArraysTools.sort(students);

        System.out.println("排序之后:");
        for (int i = 0; i < students.length; i++) {
            System.out.println(students[i]);
        }

        System.out.println("=====================================");
        Circle[] arr = new Circle[3];
        arr[0] = new Circle(1);
        arr[1] = new Circle(3);
        arr[2] = new Circle(2);

        System.out.println("排序之前:");
        for (int i = 0; i < arr.length; i++) {
            System.out.println(arr[i]);
        }

        MyArraysTools.sort(arr);

        System.out.println("排序之后:");
        for (int i = 0; i < arr.length; i++) {
            System.out.println(arr[i]);
        }
    }
}

class MyArraysTools{
/*    public static void sort(Object[] arr){
        for (int i=1; i<arr.length; i++){
            for (int j=0; j<arr.length-i; j++){
                if(arr[j] > arr[j+1]){//报错,arr[j]和arr[j+1]是对象,不能直接比较大小,如何解决
                    Object temp = arr[j];
                    arr[j] = arr[j+1];
                    arr[j+1] = temp;
                }
            }
        }
    }*/

    /*
        如何解决对象比较大小的问题?
        对象的比较只能通过对象的某个属性进行比较大小。
        问题在于,我现在都不知道arr中是什么对象,更不可能知道,按照什么属性进行比较大小。
        这个问题,只有调用者自己知道,“谁调谁知道”,即我们要把按照对象的xx属性进行比较大小的问题抛给调用者处理。

        我们这里只能定一个标准,想要用这个方法进行排序的对象,必须支持“比较”大小,
        即实现xx接口,JDK中提供了一个Comparable接口。
        表示存储数组中的元素,即要排序的对象的类型,必须实现Comparable接口


        这个接口有一个抽象方法:int compareTo(Object other)
         返回值:   .前面的对象  大于 ()中的对象,返回 正整数
         返回值:   .前面的对象  小于 ()中的对象,返回 负整数
         返回值:   .前面的对象  等于 ()中的对象,返回 0
     */
    public static void sort(Object[] arr){
        for (int i=1; i<arr.length; i++){
            for (int j=0; j<arr.length-i; j++){
                //arr数组中的元素一定实现了Comparable接口
                Comparable left = (Comparable) arr[j];//向下转型,arr[j]编译时类型是Object,向下转为Comparable
                if(left.compareTo(arr[j+1])>0){//报错,arr[j]和arr[j+1]是对象,不能直接比较大小,如何解决
                    Object temp = arr[j];
                    arr[j] = arr[j+1];
                    arr[j+1] = temp;
                }
            }
        }
    }
}

class Student implements Comparable{
    private String name;
    private int age;
    private int score;

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

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public int getScore() {
        return score;
    }

    public void setScore(int score) {
        this.score = score;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", score=" + score +
                '}';
    }

    @Override
    public int compareTo(Object other) {
        //哪两个对象比较大小,this和other
        //按照年龄排序
//        return this.age - ((Student)other).age;

        //按照年龄排序,如果年龄相同的安装成绩排序,如果成绩相同,按照姓名排序
        Student stu = (Student) other;
        if(this.age != stu.age){
            return this.age - stu.age;
        }

        if(this.score != stu.score){
            return this.score - stu.score;
        }

        //String类型实现了Comparable接口,字符串的排序是按照字符串的每一个字符的Unicode编码值,先看第一个字符,第一个字符不同按第一个排序,第一个字符一样,看第二个,依次类推
        return this.name.compareTo(stu.name);

    }
}
class Circle implements Comparable{
    private double radius;

    public Circle(double radius) {
        this.radius = radius;
    }

    public double getRadius() {
        return radius;
    }

    public void setRadius(double radius) {
        this.radius = radius;
    }

    @Override
    public String toString() {
        return "Circle{" +
                "radius=" + radius +
                '}';
    }

    @Override
    public int compareTo(Object o) {
        Circle other = (Circle) o;
        if(this.radius > other.radius){
            return 1;
        }else if(this.radius < other.radius){
            return -1;
        }
        return 0;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值