• 如果您觉得本站非常有看点,那么赶紧使用Ctrl+D 收藏吧

JAVASE(四)–面向对象(下)

互联网 diligentman 1周前 (10-16) 13次浏览

访问控制修饰符

public

允许跨工程访问的类

protected

允许同包类+子类访问

default

(不写修饰符默认隐藏)同包类

private

只允许本类访问

权限大小比较

public > protected > default > private

JAVASE(四)--面向对象(下)

this和super关键字

this

this代表本类对象的一个引用对象。

–构造函数中,this()必须放在第一行。
–当局部变量和成员变量同名时,用于区分。
–构造方法之间互相调用

public class Test_This {
    public static void main(String[] args) {
        new Demo().test();//通过对象,来访问类里的成员(成员变量和成员方法)
    }
}    
class Demo{
    int count = 20 ;//成员变量
    public void test() {
        int count = 10;//局部变量
        System.out.println(count);//10,变量的就近原则,会使用局部变量 的值 
        //想要使用  和  局部变量 同名的 成员变量count--this调用成员变量
        //this表示的是本类的对象的引用--底层帮你new了一个本类对象--Demo this = new Demo();
        System.out.println( this.count );//20,成员变量
    }
}
public class Test_This2 {
    public static void main(String[] args) {
        new Demo2(1);
        //输出:
        //无参构造
        //含参构造1

    }
}
class Demo2{
     public Demo2() {
         System.out.println("无参构造");
     }
     public Demo2(int a) {
         this();//在构造方法中,使用this关键字,必须是第一条语句
         System.out.println("含参构造"+a);
     }
}

super

super代表父类对象的一个引用对象

–通过super关键字可以使用父类的内容
–如果用super,必须出现在调用位置的第一行

public class Test_Super {
public static void main(String[] args) {
    new Zi3();    //父类无参构造
                  //子类无参构造
    new Zi3("含参"); //父类无参构造
                    //子类含参构造
}
}

class Fu3{
//如果父类有含参构造,子类找不到无参构造,需要在子类中使用super去调用父类的含参构造    
    public Fu3(String name) {
        System.out.println("父类含参构造");
    }
}
class Zi3 extends Fu3{
    public Zi3() {
        //super();如果没有super,在此处隐藏了--子类的构造方法中都会隐藏着父类的无参构造
        super("含参");
        System.out.println("子类无参构造");
    }
    public Zi3(String name) {
        //此处也隐藏了super();证明子类每一个构造都隐藏了父类无参构造
        super("含参");
        System.out.println("子类含参构造");
    }

}

this和super比较

1、 this代表本类对象的引用,super代表父类对象的引用。
2、 this用于区分局部变量和成员变量
3、 super用于区分本类变量和父类变量
4、 — this.成员变量 — this.成员方法() — this(参数)代表调用本类内容
5、 –super.成员变量–super.成员方法()–super(参数)代表调用父类内容
6、 this和super不可以同时出现在同一个构造方法里,他们两个只要出现都得放在第一行,同时出现的话,到底第一行放谁呢。。

static和final关键字

static

static用于修饰成员(变量&方法),使其成为静态资源。
特点

1、 可以修饰成员变量,成员方法
2、 随着类的加载而加载,优先于对象加载
3、 只加载一次,就会一直存在,不再开辟新空间
4、 全局唯一,全局共享
5、 可以直接被类名调用
6、 静态只能调用静态,非静态可以随意调用
7、 static不能和this或者super共用,因为有static时可能还没有对象

public class Test_Static {
    public static void main(String[] args) {
        //2,静态资源优先于对象加载,因为是随着类的加载就已经加载了
        Student.coding();//null
                        //正在敲代码
        System.out.println(Student.name);//null
        Student s = new Student();
        s.study();//10
                   //null
                   //null
                  //正在敲代码
                  //正在学习java
        System.out.println(s.age);//10
        //1,静态资源,多了一种访问方式,除了可以用对象访问,更提倡用类名直接调用
        Student.coding();//null
                          //正在敲代码
        System.out.println(Student.name);//null
        //3,静态资源是共享资源,能够被多个对象共享
        Student s1 = new Student();
        s1.name="张三";
        Student s2 = new Student();
        System.out.println(s2.name);//张三
    }
}
class Student{
    //普通资源 
    int age = 10;
    public void study() {
        //6,非静态调用关系? -- 调用任意资源
        System.out.println(age);
        System.out.println(name);
        coding();
        System.out.println("正在学习java");
    }
    //静态资源
    static String name ;
    static public void coding()  {
        //4,静态资源里,不能使用this或者super关键字!
        //this.study();
        //super.
        //5,静态调用关系? -- 只能调用静态,不能调用非静态的
        System.out.println(name);
        System.out.println("正在敲代码");
    }
}

final

final表示最终,可以修饰类、成员变量、成员方法。
特点

1、 被final修饰的类,不能被继承
2、 被final修饰的方法,不能被重写
3、 被final修饰的变量是个常量,值不能被更改
4、 常量的定义形式: final 数据类型 常量名 = 值

public class Test_Final {
    public static void main(String[] args) {
           Zi d = new Zi();
           d.speak();//Fu..speak()
           System.out.println(d.name);//欢欢
           d.test();//欢欢
    }
}
class Fu{
    //final class Fu{
    //1,被final修饰的类,不能被继承
    final String name="欢欢";
    public final void speak(){
           System.out.println("Fu..speak()");
    }
}
class Zi extends Fu{
    //public void speak(){ }
    //2,被final修饰的方法,不能被重写
    public void test(){
    //super.name="大黄";
    //3,被final的变量,不能重新被赋值
           System.out.println(super.name);
    }
}

异常

用来封装错误信息的对象(bug)。

组成结构:类型,提示,行号。

Throwable

Throwable - 顶级父类
    -Error:系统错误,无法修复
    -Exception:可修复的错误
        -RunTimeException
            -ClassCastException
            -ClassNotFoundException

Exception

程序中遇到了异常(Exception),通常有两种处理方式:捕获或者向上抛出。
当调用了一个抛出异常的方法时,调用位置可以不做处理继续向上抛出也可以捕获异常。

1.捕获异常(使用try{}catch{})
try{
    需要捕获的代码
}catch(异常类型  异常名){
    处理方案
}

测试

import java.util.InputMismatchException;
import java.util.Scanner;
//测试 异常
public class Test_Exception {
    public static void main(String[] args){
        method();//捕获异常
    }
    /* 捕获异常
     * try{ 代码... }catch(异常类型 异常名){ 合理的解决方案 }
     * 异常类型: ArithmeticException  /  InputMismatchException
     */
    public static void method() {
        try {
            int a = new Scanner(System.in).nextInt();
            int b = new Scanner(System.in).nextInt();
            System.out.println(a/b);
        }catch(InputMismatchException a) {
            System.out.println("请输入两次整数!");
        }catch(ArithmeticException a) {
            System.out.println("第二次输入的整数不能为0 !");
        }catch(Exception a) {
            //怎么捕获其他的所有异常呢?--多态--通用性强-不关心子类类型,把子类当做父类来看
            //所有Exception的子类都能被捕获!
            System.out.println("请输入正确的数据!!");
        }
    }
}

多组数据结果

0
0.1
请输入两次整数!
5
0
第二次输入的整数不能为0 !
2.抛出异常(方法上使用throws 异常类型)
main() throws InputMismatchException{}

测试

import java.util.Scanner;
public class Test_Exception2 {
    public static void main(String[] args){
        try {
            //调用了抛出异常的method2(),需要处理,捕获或者抛出二选一
        method2();//抛出异常
        }catch(Exception e) {
            System.out.println("运算错误!");
        }
    }
    /* 抛出异常
     * 在方法声明上加 throws 异常类型1,异常类型2...
     */
    public static void method2() throws Exception{
        int a = new Scanner(System.in).nextInt();
        int b = new Scanner(System.in).nextInt();
        System.out.println(a/b);
    }
}
5
0
运算错误!

代码块

被 { } 包起来的一段代码就叫代码块

构造代码块

特点

1、 在类的内部,方法外部,的代码块。
2、 通常用于抽取构造方法中的共性代码。
3、 每次调用构造方法前都会调用构造代码块
4、 优先于构造方法加载

局部代码块

特点

1、 在方法里面的代码块
2、 通常用于控制变量的作用范围,出了括号就失效
3、 变量的范围越小越好,成员变量会有线程安全问题

静态代码块

随着类的加载而加载,并且只被加载一次,一般用于项目的初始化
static{…}//在成员位置,拥有static关键字的代码块
特点

1、 静态代码块:static{ },位置:在类里方法外
2、 在类加载时就执行,不管创建多少对象,只会执行一次的代码块

执行顺序(代码块+构造方法+继承)

总体顺序:
启动程序 -> 父类静态代码块 -> 子类静态代码块 -> 子类main方法 -> new SubClass( ) -> 父类构造代码块 -> 父类构造方法中局部代码块 -> 子类构造代码块 -> 子类构造方法中局部代码块

class Parent {
    public static String p_StaticField = "父类-静态变量";
    public String    p_Field = "父类-变量";
    protected int    i = 1;
    protected int    j = 2;
    static {
        System.out.println( p_StaticField );    // 1.
        System.out.println( "父类-静态代码块" );  //2.
    }
    {
        System.out.println( p_Field );  // 7.
        System.out.println( "父类-构造代码块" );  // 8.
    }
    public Parent()
    {
        System.out.println( "父类-局部代码块" );    // 9.
        System.out.println( "i=" + i + ", j=" + j );    // 10.
        j = 3;
    }
}
public class SubClass extends Parent {
    public static String s_StaticField = "子类-静态变量";
    public String s_Field = "子类-变量";
    static {
        System.out.println( s_StaticField );    // 3.
        System.out.println( "子类-静态代码块" );  // 4.
    }
    {
        System.out.println( s_Field );  // 11.
        System.out.println( "子类-构造代码块" );  // 12.
    }
    public SubClass()
    {
        System.out.println( "子类-局部代码块" );    // 13.
        System.out.println( "i=" + i + ",j=" + j ); //14.
    }
    public static void main( String[] args )
    {
        System.out.println( "main方法开始" );   // 5.
        new SubClass(); // 6.
    }
}

执行结果:

父类-静态变量
父类-静态代码块
子类-静态变量
子类-静态代码块
main方法开始
父类-变量
父类-构造代码块
父类-局部代码块
i=1, j=2
子类-变量
子类-构造代码块
子类-局部代码块
i=1,j=3

抽象类和接口

抽象类

概念

Java中可以定义没有方法体的方法,该方法由其子类来具体的实现。该没有方法体的方法我们称之为抽象方法,含有抽象方法的类我们称之为抽象类。
特点

1、 通过java关键字abstract实现
2、 可以修饰方法或者类
3、 抽象类中可以没有抽象方法(由子类去实现)
4、 如果类中有抽象方法,那该类必须定义为一个抽象类
5、 子类继承了抽象类以后,要么还是一个抽象类,要么就把所有抽象方法都重写
6、 多用于多态中
7、 抽象类不可以被实例化

import java.io.IOException;
import java.io.Reader;
//测试 抽象类
public class Test_Abstract {
    public static void main(String[] args) {
        //创建多态对象--父类引用 指向 子类对象
        //Animal2 a = new Dog2();//8,抽象类不能被实例化
        Animal2 a = new Cat2();
        a.eat();//父类的方法声明,父类的方法体
        a.sleep();//父类的方法声明,子类的方法体(重写了)
    }
}
//1,为什么产生父类?--为了提取子类的共性,提高父类代码的复用性
//2,怎么优化父类?--程序设计--父类有没有可以省略的功能--方法体可以省略
//4,如果类里包含抽象方法,那么,这个类就是一个抽象类
//5,使用abstract关键字描述抽象
abstract class Animal2{
    public void eat() {
        System.out.println("Animal...eat()");
    }
//3,如果有方法体,写了也要被修改,那就可以省略不提供--没有方法体的方法--抽象方法
    abstract public void sleep() ;
}
//6,子类继承抽象类后,就继承来了抽象方法,是一个 抽象的 子类
abstract class Dog2 extends Animal2 {
}
//7,子类继承抽象类后,子类可以重写 所有的 抽象方法
class Cat2 extends Animal2 {
    @Override//注解,作用是用来标志这个方法是一个重写方法
    public void sleep() {
        System.out.println("猫吃鱼");
    }
}
class SubReader extends Reader{
    //抽象方法必须重写,否则就是一个抽象类
    //普通方法不是必须重写,而是要改才重写
     public void close() throws IOException{
         System.out.println("close() ");
     }
     public int read(char cbuf[], int off, int len) throws IOException{
         System.out.println("read() ");
         return 0 ;
     }
}

构造方法

1、 抽象类里有构造方法
2、 抽象类自己不能被实例化,仍然会提供构造方法,用于帮助子类初始化
3、 当创建子类对象时,会触发子类的构造方法,子类的构造方法里第一条默认就会有super()
4、 构造方法的执行顺序: 父类的 –> 子类的

public class Test_Abstract2 {
    public static void main(String[] args) {
        //2,先执行父类的 构造方法 ,再执行自己的构造方法
        Animal3 a = new Dog3();
    }
}
//创建抽象类 
abstract class Animal3{
//3,抽象类不能被实例化,为什么还要提供构造方法?--为了方便子类new
    public Animal3() {
        System.out.println("Animal3..无参构造");
    }
}
class Dog3 extends Animal3{
    public Dog3() {
        super();//1,默认就存在,会主动找父类的无参构造
        System.out.println("Dog3..无参构造");
    }
}

成员变量和成员方法

1、 既可以有变量,也可以有常量。
2、 抽象类里,既可以有普通方法,有可以有抽象方法。
3、 抽象类里可以都是普通方法,目的是不让外界实例化

测试成员变量
public class Test_Abstract3 {
    public static void main(String[] args) {
        System.out.println( new Demo2().age );//10
        //new Demo2().name = "123" ;final的常量,值不能被修改
        System.out.println( new Demo2().name );//Demo
    }
}
abstract class Demo{
    int age = 10 ;
    final String name = "Demo";
}
class Demo2 extends Demo{
    
}
测试成员方法
public class Test_Abstract4 {
    public static void main(String[] args) {
        Demo3 d = new Demo5();//Demo3 Demo4都是抽象类不能new
        d.save();//多态的目的是统一标准,一切向父类看齐
        d.delete(10);
        d.update("jack");
    }
}
//1,抽象类是一个特殊的类,特殊在 类里可以有普通方法和 抽象方法,怎么决定类里的方法到底设计成普通方法还是抽象方法呢?--看方法体有没有必要提供
abstract class Demo3{
    public void save() {
        System.out.println("数据保存成功!");
    }
    abstract public void delete(int id) ;
    abstract public void update(String name) ;
}
//2,子类继承了抽象类,只重写了一部分抽象方法,也就是还包含着抽象方法,所以仍然是一个抽象类
abstract class Demo4 extends Demo3{
     public void delete(int id) {
         System.out.println("delete().."+id);
     }
}
class Demo5 extends Demo4{
    public void update(String name) {
        System.out.println("update().."+name);
    }
}

接口

Java里面由于不允许多重继承,所以如果要实现多个类的功能,需要可以通过实现多个接口来实现。

Java接口和Java抽象类代表的就是抽象类型,就是我们需要提出的抽象层的具体表现。OOP[面向对象]的编程,如果要提高程序的复用率,增加程序的可维护性,可扩展性,就必须是面向接口的编程,面向抽象的编程,正确地使用接口、抽象类这些太有用的抽象类型做为java结构层次上的顶层。

特点

1、 接口中都是抽象方法
2、 通过interface关键字创建接口
3、 通过implements让子类来实现
4、 可以理解成,接口是一个特殊的抽象类
5、 接口突破了java的单继承的局限性
6、 接口和类之间可以多实现,接口和接口之间可以多继承
7、 接口是对外暴露的规则,是一套开发规范
8、 接口提高了程序的功能扩展,降低了耦合性

public class Test_Interface {
    public static void main(String[] args) {
        //6,接口和抽象类一样,都不可以被实例化
        Demo d = new DemoImpl();
        //7,多态对象为了统一调用标准,以父类为准
        d.save();
        d.delete();
    }
}
//1,通过interface关键字,定义接口
interface Demo{
    //2,接口里全都是抽象方法(jdk1.8后可以是default/static的普通方法)
    abstract public void save() ;
    abstract public void delete() ;
}
//3,实现类想要使用接口的功能,需要和接口发生实现关系(类似继承)
//5,实现类实现了接口,可以重写 所有 抽象方法
class DemoImpl  implements  Demo{
    @Override//注解
    public void save() {
        System.out.println("数据保存成功!");
    }
    @Override//注解
    public void delete() {
        System.out.println("数据删除成功!");
    }
}
//4,实现类实现了接口,可以是一个抽象的实现类
//abstract class DemoImpl  implements  Demo{}

接口的使用

构造方法

接口里是没有构造方法的。在创建实现类的对象时默认的super(),是调用的默认Object的无参构造。

成员变量

接口里没有成员变量,都是常量。所以,你定义一个变量没有写修饰符时,默认会加上public static final

成员方法

接口里的方法–都是抽象方法(java1.8前);
可以有static或者default的普通方法(java1.8后)

public class Test_Interface2 {
    public static void main(String[] args) {
        //3,使用接口里的静态常量?
        //Inter.age = 30 ;//是final的常量
        System.out.println( Inter.age );//20,是static的资源
        System.out.println( new InterImpl().age );//20
        Inter in = new InterImpl();
        in.show();//这是jdk1.8的新特性
        in.save();//数据保存成功!
        Inter.test();//这是jdk1.8的新特性--通过类名直接访问接口里的普通的静态方法
    } 
}
interface Inter{
    //1,接口里有没有构造方法?--没有--实现类到底怎么new的?--
    //2,接口里有没有变量?--没有!!是static的final的常量public的
    //public static final int age = 20 ;//接口会为你的变量,自动拼接public static final 
    int age = 20 ;//简写形式
    //4,接口里有没有普通方法?--有,只不过是jdk1.8才提供的,必须修饰成default/static
    default public void show() {
        System.out.println("这是jdk1.8的新特性");
    }
    static public void test() {
        System.out.println("这是jdk1.8的新特性");
    }
    //5,接口里有没有抽象方法?--有
    //abstract public void save() ;//接口会为你的抽象方法,自动拼接public abstract
    void save() ;//简写形式
}
//6,实现类实现接口后,对于普通方法必须重写吗?--不是,要改才重写
//7,实现类实现接口后,对于抽象方法必须重写吗?--是,否则就是一个抽象的实现类
class InterImpl extends Object implements Inter{
    public InterImpl() {
        //不是接口里的构造方法,因为接口根本没有构造方法,其实找的是Object的构造方法
        super();
    }
    @Override
    public void save() {
        System.out.println("数据保存成功!");
    }
}

接口复杂用法

1、 接口之间可以多继承,多个接口之间逗号隔开(打破了java单继承的局限性,)
2、 接口还可以多实现,只不过接口之间逗号隔开
3、 接口甚至还可以单继承的同时多实现

import java.io.Reader;
public class Test_Interface3 {
    public static void main(String[] args) {
        //2,左侧写的接口到底是谁?--要看你想用哪个接口的功能,左侧就写谁
        Inter2 in = new Inter2Impl() ;
        in.save();//数据保存成功!
        int rows = in.update(2) ;//数据已经更新
        System.out.println(rows);//5
        System.out.println( in.update(2) );//数据已经更新
                                           //5
        in.delete("jack");//删除记录成功!jack
    }
}
interface Inter1{
    void save();
    int update(int id);
}
interface Inter3{
    void delete(String name);
}
//1,接口间是继承关系,而且可以多继承
interface Inter2 extends Inter1 , Inter3{
    
}
//4,实现类和接口,是实现关系,还可以多实现
class Inter3Impl implements Inter3 , Inter1 {
    public void delete(String name) {
        System.out.println("删除成功!");
    }
    public void save() {
        System.out.println("保存成功!");
    }
    public int update(int id) {
        System.out.println("更新成功!");
        return 5;
    }
}
//5,实现类可以在单根继承的同时,多实现
//Inter4Impl需要重写Inter1和Inter3里的 所有抽象方法,否则就是一个抽象类
abstract class Inter4Impl extends Object implements Inter1 , Inter3{
    
}
//3,实现类,实现了接口.需要把接口里 所有抽象方法都重写.
//Inter2接口里的3个方法都要重写
class Inter2Impl implements Inter2{
    @Override
    public void delete(String name) {
        System.out.println("删除记录成功!"+name);
    }
    @Override
    public void save() {
        System.out.println("数据保存成功!");
    }
    @Override
    public int update(int id) {
        System.out.println("数据已经更新");
        return 5;
    }
}

抽象类和接口的区别

相同点

1、 都可以出现抽象方法
2、 都不能被实例化
3、 都需要子类重写抽象方法
4、 接口和抽象类体现了继承结构里的抽象层

不同点

1、 抽象类里有构造方法,用来给子类创建对象.接口里没有构造方法.
2、 抽象类里有变量,但是接口里,只有常量,会为简写的常量自动拼接public static final
3、 抽象类里有普通方法,但是接口里,都是抽象方法(除了jdk1.8)
4、 接口里的抽象可以简写,会为简写的抽象方法自动拼接public abstract
5、 抽象类只能是和子类之间发生单根继承关系
6、 接口和实现类之间是实现关系,而且可以多实现
7、 接口和接口之间是继承关系,而且可以多继承
8、 接口是为了突破java单继承的局限性来的


喜欢 (0)