面向对象高级

1.抽象类

在面向对象的概念中,所有的对象都是通过类来描绘的,但是反过来,并不是所有的类都是用来描绘对象的,如果一个类中没有包含足够的信息来描绘一个具体的对象,这样的类就是抽象类。

1.1抽象类

抽象类在class前用abstract修饰,抽象类不能被实例化

public abstract class Animal(){
    
}

也有人把抽象称为Java面向对象的第四大特征,使用抽象类就是为了方便其他类去继承,实现多态

1.2抽象方法

抽象方法在返回值前用abstract进行修饰,抽象方法没有方法体,形如

public abstract void rap(){}

继承抽象类就要重写抽象类中的抽象方法

1.3抽象类和抽象方法的联系

抽象类中可以有抽象方法也可以有非抽象方法,除了不能实例化以外和普通的类一样

抽象类的子类必须重写抽象类中所有的抽象方法,除非子类也是一个抽象类

有抽象方法的类一定是抽象类,但抽象类不一定有抽象方法

2. 接口

接口就是一种规范, 如 USB 接口,Type-C接口,

通过接口,我们可以指定一些规范,如可以规定方法名,返回值类型,方法的形参等等

2.1接口的定义

接口使用关键字interface来定义

public interface 接口名{
	//定义抽象方法
    void method();
}

接口就是定义了一些规范,需要其他类去实现这些规范,所以接口只能是public的,接口中的方法也都是默认是public abstract 的

public interface Animal{

	void sing();//虽然没写为public abstract void sing();
	
	void jump();
	
	void rap();
	
	void basketball();
	
}
2.2实现接口

接口只是定义了一些规范,需要类实现接口,来重写接口中的各种抽象方法

实现接口需要用到implement关键字,格式如下

public class 类名 implement 接口名1,接口名2...,接口名n{}

不同于继承,一个类可以实现多个接口,多个接口名之间用逗号隔开

实现接口必须要实现接口中的所有抽象方法

public class Chicken implements Animal {
    String name = "菜徐琨";
    @Override
    public void sing() {
        System.out.println(this.name + "在唱");
    }
    @Override
    public void jump() {
        System.out.println(this.name + "在跳");
    }
    @Override
    public void rap() {
        System.out.println(this.name + "在rap");
    }
    @Override
    public void basketball() {
        System.out.println(this.name + "在打篮球");

    }
}
2.3 接口中的成员
2.3.1常量和抽象方法

jdk7 及以前版本,接口中只能有常量和抽象方法

public interface True {
    String NAME = "丁真";
    void smoke();
}

接口中定义的成员变量默认是public static final,即我们只能在接口中定义一个常量

2.3.2默认方法

jdk8中,允许我们在接口中定义默认方法.

默认方法格式如下

public interface True {

    default void listen(){
    	//方法体
    	System.out.println("芝士雪豹");
    }
}

默认方法用关键字default修饰,允许方法有方法体

类在实现接口时,可以不重写默认方法

注意:

如果两个接口中有相同的默认方法,一个类同时实现了这两个接口,则必须要重写默认方法

在接口升级的时候如果某些方法不想让所有实现类进行重写,可以把方法定义为默认方法

2.3.3 静态方法

jdk8中,我们可以去定义静态方法,静态方法有方法体且不能被重写

public interface True {
    
    static void smoke(){
    	System.out.println("我是电子香烟的代表者丁真");
    }
    
}

接口静态方法的使用与类中静态方法的使用类似

通过接口名.方法名(实参)来进行调用

public class Test {
    public static void main(String[] args) {
        True.smoke();
    }
}
2.4 继承与实现的关系

在之前学习继承我们已经了解到,Java类只能单继承,但一个Java类可以实现多个接口,通过这种方法可以做到与C++类似的多继承

Java中接口之间也可以进行继承,通过关键字extends

public interface Animal{
    void sing();
    void jump();
    void rap();
    void basketball();
}
public interface Chicken extends Animal{}

接口继承另一个接口后,可以不重写其中的抽象方法

2.5 抽象类与接口的区别和联系

区别:

  • 抽象类中的方法基本都是抽象的,但抽象类中可以存在非抽象方法.
  • 抽象类中可以定义成员变量,但接口中只能定义常量
  • 一个类只能继承一个抽象类,但是可以实现多个接口
  • 抽象类中可以有构造方法,接口中没有

联系:

  • 都可以含有抽象方法
  • 都不能被实例化
  • 都是为了多态的使用,为了被其他类继承实现

3.代码块

在之前我们已经了解到类的组成包括成员变量,成员方法,构造方法

代码块也是类的一个组成部分,在Java类中用{}包裹的代码就称为代码块

代码块按照位置和声明的不同,可以分为局部代码块,静态代码块,实例代码块和同步代码块

3.1 局部代码块

局部代码块写在方法中,用{}包裹,如下

public static void main(String[] args) {
    	//一个局部代码块
        {
            String name = "雪豹";
            System.out.println("芝士"+name);//输出芝士雪豹
        }
        System.out.println("芝士"+name);//无法访问到name
}

作用:

局部代码块可以用于限定变量的生命周期,让变量尽早释放,从而提高内存的利用率

3.2 静态代码块

静态代码块写在类中,用static修饰,如下

public class Demo02 {
    public static void main(String[] args) {
        System.out.println("王源喜欢传统香烟");
    }
    static {
        System.out.println("丁真喜欢电子香烟");
    }
    //输出:
    //丁真喜欢电子香烟
	//王源喜欢传统香烟
}

之前我们了解到,被 static 修饰表示是静态的,

静态代码块也是一样,在类加载时进行,与类一起进行加载,在执行类和加载类时都会执行一次静态代码块

而且静态代码块是自动触发的,在程序启动时静态代码块就会执行一次

作用:

由于静态代码块在类加载和类执行时就会执行的这种特性,一般用于初始化静态资源

3.3 实例代码块(构造代码块)

实例代码块写在类中,如下

public class Demo {
    public String name;
    {
        name = "老八";
        System.out.println("实例代码块被执行");
    }

    public Demo(String name) {
        System.out.println("有参构造方法被调用");
        this.name = name;
    }

    public Demo() {
        System.out.println("无参构造方法被调用");
    }

}
public class Test {
    public static void main(String[] args) {
        Demo demo1 = new Demo();
        Demo demo2 = new Demo("李易峰");
        System.out.println(demo1.name + "在吃奥利给");
        System.out.println(demo2.name + "在pc");
    }
    	//实例代码块被执行
		//无参构造方法被调用
		//实例代码块被执行
		//有参构造方法被调用
		//老八在吃奥利给
		//李易峰在pc
}

实例代码块在创建对象时执行,每次调用构造方法来初始化对象,实例代码块都会执行一次

通过上述代码我们也可以知道,实例代码块的执行在构造方法之前

3.4 静态代码块,实例代码块,构造方法的执行顺序
//父类Person
public class Person {
    public Person() {
        System.out.println("Person构造器被调用");
    }
    static {
        System.out.println("Person静态代码块被调用");
    }
    {
        System.out.println("Person实例代码块被调用");
    }
}
//子类Men
public class Men extends Person{
    public Men() {
        System.out.println("Men构造方法被调用");
    }
    static{
        System.out.println("Men静态代码块被调用");
    }
    {
        System.out.println("Men实例代码块被调用");
    }
}
//测试执行顺序
public class Test05 {
    public static void main(String[] args) {
        Men men = new Men();
    }
    //Person静态代码块被调用 
	//Men静态代码块被调用
	//Person实例代码块被调用
	//Person构造器被调用
	//Men实例代码块被调用
	//Men构造方法被调用
}

通过上述代码我们可以知道执行顺序是

父类静态代码块 -> 子类静态代码块 ->父类实例代码块->父类构造方法->子类实例代码块->子类构造方法

4 内部类

定义在类内部的类被称为内部类.内部类可分为局部内部类,成员内部类,静态内部类,匿名内部类

4.1 局部内部类

局部内部类就是定义在方法中的类

public class Men {
    String name = "丁真";
    public void smoke() {
        class True {//局部内部类
            public void smoke() {
                System.out.println(name + "喜欢抽瑞克五代");
            }
        }
    }
}

对象创建需要在方法内部进行,如下

public class Men {
    String name = "丁真";
    public void smoke() {
        class Inner {
            public void smoke() {
                System.out.println(name + "喜欢抽瑞克五代");
            }
        }
        Inner inner = new Inner();
        inner.smoke();
    }
}
public class Test {
    public static void main(String[] args) {
        Men men = new Men();
        men.smoke();
    }
}

如果想要定义一个在方法中临时使用的类就可以用局部内部类,局部内部类的作用范围只在方法内

4.2 成员内部类

定义类中的非static的内部类称为成员内部类

public class Phone {
   public class HaWei{
       public String des = "华为13proMax远峰蓝1TB";
   }
}
4.2.1 成员内部类对象的创建

在类内部和之前学习的创建对象方法一致

public class Phone {
   public class HaWei{
       public String des = "华为13ProMax 1TB 远峰蓝";
       public HaWei(String des) {
           this.des = des;
       }
       public HaWei() {
       }
   }
   public HaWei haWei = new HaWei();
}

在类外部创建对象有些繁琐

public class Test05 {
    public static void main(String[] args) {

        Phone phone = new Phone();
        Phone.HaWei haWei1 = phone.new HaWei("华为14ProMax 1TB 暗夜紫");
        
        Phone.HaWei haWei2 = new Phone().new HaWei();//简化写法
        System.out.println(haWei1.des);
        System.out.println(haWei2.des);
    }
}

可能看起来这种写法有些怪,但是仔细思考

成员内部类属于类的一个成员,所以需要创建对象来使用,

而成员内部类也需要创建对象来访问其中的成员变量和成员方法

4.2.2 成员内部类的特点
  1. 成员内部类中不能定义静态成员,

  2. 因为成员内部类是非静态的,在非静态中不能使用静态的

    在成员内部类中可以使用类中的变量和方法,即使是私有的

public class Phone {
    private double price = 12999.9;
    String name = "华为14ProMax 1TB 暗夜紫";
    public class HaWei {
        public void price() {
            System.out.println("\"" + name + "\"" + "价格是" + price);
        }
    }
}

public class Test {
    public static void main(String[] args) {
        Phone.HaWei haWei = new Phone().new HaWei();
        haWei.price();//"华为14ProMax 1TB 暗夜紫"价格是12999.9
    }
}
  1. 如果外部类和内部类的变量重名,可以使用外部类名.this.成员变量来访问
public class Phone {
    private double price = 12999.9;
    String name = "华为14ProMax 1TB 暗夜紫";
    public class HaWei {

        String name = "华为13ProMax 1TB 远峰蓝";
        public void price() {
            System.out.println("\"" + Phone.this.name + "\"" + "价格是" + price);
        }
    }
}
4.3 静态内部类

在类中用static修饰的内部类称为静态内部类

public class Person {
    public static class White{
        public static String name = "土块";
        public String des = "十七张牌你能秒我?"
        public static void say(){
            System.out.println(name +"给阿姨倒一了杯卡布奇诺");
        }
        public void sit(){
            System.out.println("全体起立");
        }
    }
}
public class Test {
    public static void main(String[] args) {
        Person.White.say();
        Person.White white = new Person.White();
        white.sit();
        //土块给阿姨倒一了杯卡布奇诺
		//全体起立
    }
}

静态内部类中可以定义静态成员变量和普通成员变量,也可以定义静态方法和成员方法

在使用时,静态变量和静态方法无需新建对象,成员变量和成员方法的使用需要新建对象

4.4 匿名内部类

匿名内部类就是没有名字的内部类,实质上是一个对象,格式如下

new 接口名/类名(){
      	//重写要重写的方法  
    };

当我们需要创建一个类或接口的子类对象,但是这个子类只需使用一次时,

就可以考虑使用匿名内部类,而不是单独创建一个类.

//定义一个接口
public interface Star {
    void pc();
}

public class Test {
    public static void main(String[] args) {
        Star star = new Star() {
            @Override
            public void pc() {
                System.out.println("加藤峰在pc");
            }
        };
        star.pc();
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值