面向对象的

面向对象

概念解析

什么是面向对象?

开发过程中,以声明的标准或者逻辑编写程序
	1.面向对象——>(老板)
	对象就是打工人,什么人面向打工人呢——>当然是老板
	2.面向过程(打工人)
例如:《张三想开门》  
面向过程的逻辑是:我起身离开座位——>走到门前——>开门
面向对象的逻辑是:我叫张三去开门,张三重复上面的过程。



具体解释
面向对象:只需要负责使用该对象,不需要关系对象的具体执行逻辑,所以方便使用者去调用。比较擅长完成负责的业务功能。强调的使用或者调用。

面向过程:所有执行步骤都是按部就班的,在整个逻辑中不能随意修改步骤,不然就可能出现问题。但是它是解决问题的最基础的方案。强调的是完成。

面向对象的具体解释

对象和类的概念解释

类:一个模板(类似于图纸),通过这个图纸可以源源不断产生对象,用图纸可以批量造出东西(即对象),例如:用飞机蓝图不断的可以造出飞机

对象:具体的事物,;比如飞机 ;飞机就是一个对象

(类似于先有鸡还是先有蛋):不确定

如果按照 代码构建 的角度思考:
	先有对象,通过将多个对象的共性抽取出来,将其归为一类; 这个角度我们发现先有对象 才有的类
	
如果按照 编写代码 的角度思考:
	先有类,再有对象。定义类之后,通过`类名 变量名 = new 类名()` 创建一个类的实例独享。

类和对象的声明

声明 类:

将当前 类 可能产生的对象的相同点罗列出来:

外在的表现————>定义成为类中的变量

内在的功能————>定义成为类中的一个方法 ,这个方法不能加static的关键词的

public class Computer {
    /* 属性 */
    int price;
    String type;
    String color;

    /* 功能 */
    public void playGame(){
        System.out.println("玩游戏");
    }

    public void info(){
        System.out.println("price:"+price);
    }
}

声明 对象:

声明对象的方式:类名 变量名 = new 类名()

对象.属性

对象.方法

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

        Computer c1 = new Computer();
        c1.price = 123456; 

        c1.playGame();
        c1.info();
    }
}

java中的变量,局部、成员、 静态、 常量

局部变量:

概念:在方法内声明的变量被称为局部变量,该变量只能在该方法内使用,类中的其他方法并不知道该变量

注意事项:

  • 局部变量声明在方法、构造方法或者语句块中。

  • 局部变量在方法、构造方法、或者语句块被执行的时候创建,当它们执行完成后,将会被销毁。

  • 访问修饰符不能用于局部变量。

  • 局部变量只在声明它的方法、构造方法或者语句块中可见。

  • 局部变量是在栈上分配的。

  • 局部变量没有默认值,所以局部变量被声明后,必须经过初始化,才可以使用。

成员变量:

概念:在类内部但在方法体外声明的变量,称为成员变量,或者实例变量。之所以称为实例变量,是因为该变量只能通过类的实例(对象)来访问。

注意事项:

  • 成员变量声明在一个类中,但在方法、构造方法和语句块之外。

  • 当一个对象被实例化之后,每个成员变量的值就跟着确定。

  • 成员变量在对象创建的时候创建,在对象被销毁的时候销毁。

  • 成员变量的值应该至少被一个方法、构造方法或者语句块引用,使得外部能够通过这些方式获取实例变量信息。

  • 成员变量可以声明在使用前或者使用后。

  • 访问修饰符可以修饰成员变量。

  • 成员变量对于类中的方法、构造方法或者语句块是可见的。一般情况下应该把成员变量设为私有。通过使用访问修饰符可以使成员变量对子类可见;成员变量具有默认值。数值型变量的默认值是 0,布尔型变量的默认值是 false,引用类型变量的默认值是 null。变量的值可以在声明时指定,也可以在构造方法中指定。

静态变量:

概念:通过static关键字声明的变量被称为静态变量(类变量),它可以直接被类访问

注意事项:

  • 静态变量在类中以 static 关键字声明,但必须在方法构造方法和语句块之外。

  • 无论一个类创建了多少个对象,类只拥有静态变量的一份拷贝。

  • 静态变量除了被声明为常量外很少使用。

  • 静态变量储存在静态存储区。

  • 静态变量在程序开始时创建,在程序结束时销毁。

  • 与成员变量具有相似的可见性。但为了对类的使用者可见,大多数静态变量声明为 public 类型。

  • 静态变量的默认值和实例变量相似。

  • 静态变量还可以在静态语句块中初始化。

常量:

概念:有些数据的值不会发生改变的,这些数据被叫做常量——使用final关键字修饰的成员变量。

构造器

构造器是一个特殊的方法:懒人方法

  • 构造器的主要作用:完成对新对象的初始化(即给对象赋值)。

所以说这个对象的是已经创建好了,空间已经有了,构造器只是给对象赋值的。

简化了代码格式
public class Class003_Elephant {
    public static void main(String[] args) {
       
    //没用构造器之前,是这样赋值的↓↓  一个一个的赋值,且相互之间没有联系。
        Elephant ele = new Elephant();
        ele.name="胖胖";
        ele.type = "非洲象";
        ele.color = "粉色";
        //当你想 一次性 输出一个学生的编号,姓名,年龄...的时候,构造器就有了用武之地了。
class Elephant{
    public String name;   public String type;    public String color; 
}
// ps: 构造器的名称必须与类名相同
//      构造器的作用是初始化 
public class Class003_StudentTest {
    public static void main(String[] args) {
        //这就是使用了构造器的样子,超级偷懒的
        Student s1 = new Student(1001, "张三", 18);
        Student s2 = new Student(1002, "李四", 18);
}}
class Student {
    public int id;
    public String name;
    public int age;
    //这里是————————————————————————————↓↓↓构造器
    public Student(int id, String name, int age) {
        this.id = id;
        this.name = name;
        this.age = age;
    }

多个构造器

package Test.test001;
public class Class001_test {
    public static void main(String[] args) {
        Person p1 = new Person("薛师傅","爱吃炸鸡",18);//第一个构造器起了作用
        Person p2 = new Person("薛师傅")//第二个构造器起了作用,第一个就没用到
    }
}
class Person{
    String name; String love;  int age;
    //第一个构造器:
    public Person(String Pname,String Plove,int Page){
        age = Page ;  name = Pname;  love = Plove;
    }//第二个构造器:
    public Person(String Pname){
        name = Pname;
    }
    }
}

无参构造器

(即无参数)

  • 一旦定义了自己的构造器,默认的构造器(即无参构造器)就被覆盖了,就不能使用默认的无参构造器了

即不能使用 Person p1 = new Person()这样定义对象了

package Test.test001;
public class Class001_test {
    public static void main(String[] args) {
        Person p1 = new Person();//【2】除非你再显示定义一下就可以用了
		
    }
}
class Person{
    String name; String love;  int age;
    
    //【3】显示的定义无参构造器
    Public Person(){       
    }
    // 【1】一旦定义了自己的构造器,默认的构造器(即无参构造器)就被覆盖了,就不能使用默认的无参构造器了
    //  即不能使用 Person p1 = new Person()这样定义对象了
    public Person(String Pname){
        name = Pname;
    }
    }
}
1: 这个方法 没有返回值 也不需要编写返回值类型,更不需要写return语句,return语句可以用来停止方法。
2:这个方法的方法名称和当前的类是同名
3: 这个方法默认情况下在每个类中都存在默认的空参数的方法。称之为默认构造器
4:每个类中如果存在带参构造器,那么原本的空构造器就不存在了,如果你想让他存在,自己需要手动的显式定义空构造器。构造器是支持重载的
5: 构造器之间要互相调用不能直接通过方法名调用,必须要使用this()进行调用

流程分析(加了构造器)

class Person{
	int age = 90;   String name;
	Person(String a,int b){
	name = a;  age = b;
	}}
Person p = new Person("小薛",18);

Person p = new Person("小薛",18);

**1、**new的时候,在堆中开辟了一个空间,空间的地址是0x11。会有一个默认值在空间里面.

int类型:0 String类型:null double类型:0.0

**2、**开完之后,开始初始化对象,把默认值替换为你赋的值。例如(age=90),把90赋值给age。而name没有赋值则还是为null。

**3、 ** 最后到执行构造器时,把小薛传给a,把18传给b,形参ab再把值赋给name 和 age,通过这样实现赋值。然后把对象在堆中的地址返回给 p

this关键字

this. 代表当前对象(谁在调用构造器,当前对象指的就是谁)

  • this关键字可以用来访问本类的属性 方法 构造器

  • this用于区别当前类的属性和局部变量

  • this不能在类定义的外部使用,只能在类定义的方法中使用(因为this是跟对象关联的)

class Person{
	int age = 90;   
    String name;
	Person(String name,int age){
	this.name = name;  //当前对象的 属性name  
     this.age = age;   //当前对象的 属性age
        //  name = Pname;
        //  age = Page;        
	}
    
    
    public void f1(){
        String name = "smith";//传统方式会根据就近原则找到这个 smith。而不会去找你new的对象的值 小薛
        //传统方式:
        System.out.println("name"+name+"age"+age);
        //使用this访问属性:而this会非常准确的找到你对象的值
        System.out.println("name"+this.name+"age"+this.name);
    }
}
Person p = new Person("小薛",18);
  • 访问成员方法的语法:this.方法名(参数列表)

this.f1()//this调用
  • 访问构造器语法:this(参数列表)注意只能在构造器中使用

(只能在构造器中使用(即只能在构造器中访问另外一个构造器))

 class T1{
    public T1(){
        //这里是去访问T1(String name ,int  age)
        this("jack",100);//this语句一定要处于第一条语句
        System.out.println("T() 构造器");
    }
    public T1(String name,int age){    //被访问了
        System.out.println("T(String name,int age)构造器");
    }
 }

final关键字

对于变量:final关键字可以用来修饰变量,表示该变量的值一旦被初始化后便不能再被修改。一般使用全大写字母来表示final变量。
对于方法:final关键字可以用来修饰方法,表示该方法不能被子类重写。
对于类:final关键字可以用来修饰类,表示该类不能被继承。

代码块

**理解:**相当于另外一种形式的构造器(对构造器的补充机制),可以做初始化的操作

场景:如果有个构造器中都有重复语句,可以抽取到初始化块中,提高代码的重用性

快速入门:

  • 构造块是先于构造器被调用的

//解读:下面三个构造器都有相同的语句,这样代码看起来比较冗余 
//解决:我们可以把相同的语句,放到一个代码块中,即可。
//      这样当我们不管调用哪个构造器,创建对象,都会先调用代码块的内容 
{
        System.out.println("电影屏幕打开...");                        
        System.out.println("广告开始了"); 
        System.out.println("电影正式开始...");     
}
class Movie{                                                    
    public String name;                                         
    public  double price;                                       
    public  String director;                                                          
    {
      System.out.println("电影屏幕打开...");                        
      System.out.println("广告开始了"); 
      System.out.println("电影正式开始...");     
     }
  
    //3个构造器===》重载                             
    public Movie(String name) {                                 
     /*   System.out.println("电影屏幕打开...");                        
        System.out.println("广告开始了"); 
        System.out.println("电影正式开始..."); */
        this.name = name;                              
    }                                                   
    public Movie(String name, double price) {                   
  /*      System.out.println("电影屏幕打开...");                        
        System.out.println("广告开始了");                            
        System.out.println("电影正式开始...");     */      
        this.name = name;                               
        this.price = price;                             
    }                                                  
    public Movie(String name, double price, String director) {  
     /* System.out.println("电影屏幕打开...");                        
        System.out.println("广告开始了");                            
        System.out.println("电影正式开始...");     */                   
        this.name = name;                                       
        this.price = price;                                     
        this.director = director;                                                                     
    }                                                           
}                                                               

static

静态代码块作用:对类进行初始化(跟对象无关),而且随着类的加载而执行,并且只会执行一次。如果是非静态代码块(就上面的那种),每创建一个对象,就执行一次。

(类加载指的是将class文件读入内存,只会执行一次)

静态方法

当我们在一个方法前添加了static关键字,它就成为了一个静态方法。静态方法属于类,不属于实例对象。它们在类加载时就已经存在了,可以直接使用,无需创建对象。我们可以通过类名直接调用静态方法,而不需要创建类的实例对象。

public class MyClass {
    public static void staticMethod() {
        System.out.println("This is a static method");
    }
}

MyClass.staticMethod(); // 调用静态方法

静态变量:

当我们在变量前添加了static关键字,它就成为了一个静态变量。静态变量属于类,不属于实例对象。它们在类加载时就已经存在了,可以直接使用,无需创建对象。静态变量可以被类的所有实例对象共享。

public class MyClass {
    public static int staticVariable = 10;
}

MyClass obj1 = new MyClass();
MyClass obj2 = new MyClass();
System.out.println(obj1.staticVariable); // 输出 10
System.out.println(obj2.staticVariable); // 输出 10
obj1.staticVariable = 20;//被重新赋值后就改变了
System.out.println(obj1.staticVariable); // 输出 20
System.out.println(obj2.staticVariable); // 输出 20

静态代码块:

当我们在类中使用static关键字定义了一个代码块,它就成为了一个静态代码块。静态代码块在类加载时执行,并且只执行一次。

public class MyClass {
    static {
        System.out.println("This is a static block");
    }
}
MyClass obj = new MyClass(); // 输出 This is a static block

静态内部类:

当我们在类中使用static关键字定义了一个内部类,它就成为了一个静态内部类。静态内部类不依赖于外部类的实例对象,可以直接访问外部类的静态成员和方法。

public class OuterClass {
    static class InnerClass {
        public static void staticMethod() {
            System.out.println("This is a static method ");
        }
    }
}
OuterClass.InnerClass.staticMethod(); // 调用静态方法

类什么时候被加载【重要】:

  • 创建对象实例时(new)

  • 创建子类对象实例,父类也会被加载,而且父类先被加载,子类后加载

class AA extends BB{
    //静态代码块
    static {
        System.out.println("AA 的静态代码1被执行...");
    }
}
//父类
class BB {
    //静态代码块
    static {
        System.out.println("BB 的静态代码1被执行...");
    }
}
  • 使用类的静态成员时(静态属性,静态方法)

        System.out.println(Cat.n1);
class Cat{
    public static int n1 = 317;
}
  • 创建一个对象是,在 一个类 调用的顺序(重难点

1、调用静态代码块和静态属性初始化(优先级最高)静态的跟类相关,类一般都是最先被加载的

(注意:静态代码块 和 静态属性初始化 调用的优先级一样,如果有多个静态代码块和多个静态变量初始化,则按题目定义的顺序调用)

2、调用普通代码块和普通属性的初始化

(注意:普通代码块 和 普通属性初始化 调用的优先级一样,如果有多个普通代码块和多个普通变量初始化,则按题目定义的顺序调用)

3、调用构造器(优先级最低

4、构造器的最前面其实隐含了super()调用普通代码块(优先于构造器和普通代码块)

        A a1 = new A();
//输出顺序是:
getN1被调用...
静态代码块被调用了
getN2被调用...
普通代码块被调用了
A() 被调用

public class CodeBlockDetail02 {
    public static void main(String[] args) {
        A a1 = new A();
    }
}
class A{
    //普通属性的初始化↓
    public int n2 = getN2();
    {   //普通代码块↓
        System.out.println("普通代码块被调用了");
    }
    public int getN2(){
        System.out.println("getN2被调用...");
        return 200;
    }
    //静态属性的初始化
    public static int n1 = getN1();
    static {//静态代码块
        System.out.println("静态代码块被调用了");
    }
    public static int getN1(){
        System.out.println("getN1被调用...");
        return 100;
    }
    //构造器
    public A(){
    //底层代码中这里有隐藏的执行要求
    //1、super()
    //2、调用普通代码块
        System.out.println("A() 被调用");
    }
}
  • 出现继承关系,他们的静态代码块、静态属性初始化、普通代码块、普通属性初始化、构造方法的调用顺序如下:

  1. 父类的静态代码块和静态属性(优先级一样,按定义顺序执行)

  1. 子类的静态代码块和静态属性(优先级一样,按定义顺序执行)

  1. 父类的普通代码块和普通属性初始化(优先级一样,按定义顺序执行)

  1. 父类的构造器

  1. 子类的普通代码块和普通属性初始化(优先级一样,按定义顺序执行)

  1. 子类的构造器

访问修饰符

  • 公开级别:用public修饰,对外开放

  • 受保护级别:用protected修饰,对子类和同一个包(同文件夹下)中的类公开

  • 默认级别:没有修饰符号,向同一个包的类公开

  • 私有级别:用private修饰,只有类本身可以访问,不对公开

修饰符可以用来修饰类中的 属性成员方法以及
只有 默认的和public才能修饰类,并且遵循上述的访问规则
成员方法的访问规则和属性完全一样

封装

官方:封装就是把抽象出的数据(即属性)和对数据的操作(即方法)封装在一起,数据被保护在内部,程序的其它部分只有通过被授权的操作[方法],才能对数据进行操作。

好处:1、隐藏了实现的细节。2、可以对数据进行验证,保证安全合理

  • 实现3步骤:主题思想就是在方法内加入限制条件

  • 私有化:就是要求别人不能直接处理,例如private int num; 加了private,就不能直接赋值给num(即num = 317)而是需要满足方法内设置的一些条件。

  1. 将属性私有化private(使之不能直接修改属性)

  1. 提供一个公共的(public)方法,例如set方法,由于对属性判断并赋值

public void setXxx(类型 参数名){// Xxx 表示某个属性
//加入数据验证的业务逻辑
属性 = 参数名
}

3.提供一个公共的(public)t方法,例如get方法,用于获取属性的值

public 数据类型 getXxx() {// 权限判断 Xxx 某个属性
return xx;
}
//部分代码,详情找 代码.md 
fuzhi(){
    }
    fuzhi(String name,double code,String pwd){
        this.setName(name);
        this.setCode(code);
        this.setPwd(pwd);
    }
    public String getName() {
        return name;
    }
            //名字
    public void setName(String name) {
        if (name.length()>=2 && name.length()<=4 ){
            this.name = name;
        }else{
            System.out.println("您输入的名字格式错误!");
        }
    }

继承(重点)

为什么需要继承:降低写代码的重复性!

继承的基本语法:
class 子类 extends 父类{
}
  • 子类会自动拥有父亲定义的属性和方法

父类又叫 超类 基类。

子类又叫派生类。

概念图:

案例:

他两的父类:

大学生类:

小学生类:

测试:

细节问题:

1、子类继承了所有的属性和方法(不继承父类的构造方法,但可以调用),但是私有属性和方法不能在子类直接访问,要通过父类公共的方法去访问,非私有的属性和方法可以在子类中直接访问

  • 调用私有private的属性,使用公共的public方法曲线救国调用。

  • 方法也是一样。

注意事项:

  • 1.子类必须调用父类的构造器,完成父类的初始化

  • 2.当创建子类对象时,不管子类使用的哪个构造器,默认情况下总会去调用父类的无参构造器。

  • 3.如果父类没有提供无参构造器,则必须在子类的构造器中用super去指定父类的哪个构造器完成对父类的初始化工作,否则编译不会通过。

  • 4.如果希望指定去调用父类的某个构造器,则显示的调用一下:super(参数列表),上面的图有提到

  • 5.super在使用时,需要放在构造器第一行。

  • 6.super()和this()都能放在构造器的第一行,因此两个方法不能共存在一个构造器里。

  • 7.(仅了解)java所有的类都是object类的子类,object是所有类的基类

  • 8.(仅了解)父类构造器的调用不限于直接父类!将一直网上追溯指导object类(顶级父类)

  • 9.子类最多只能继承一个父类(指直接继承),即一个好大儿就只能有一个父亲 , java中是单继承机制,不能有干爹

继承的本质分析:(还没看完 在p294)

方法重写/覆盖(override)

基本介绍:

方法重写/覆盖就是子类有一个方法,和父类的某个方法名称返回类型参数一样,那么我们就说子类的方法覆盖了父类的方法,但是父类的方法并没有改变,可以通过super调用

public void aaa(){  //父类中的方法
    System.out.println("我有一个好大儿")
}
//子类中的方法
public void aaa(){
    super.aaa();//调用父类中的方法
     System.out.println("世间无我这般人")
}
//最后输出的是子类方法中的   "世间无我这般人",父类中的被覆盖了。

需满足的条件:

  1. 子类方法的 方法名称 参数 == 父类方法的 方法名称 参数

  1. 子类的返回类型和父类的返回类型一样,或者是父类返回类型的子类

比如:父类的返回类型是object ,子类方法的返回类型是String 这样也是允许的。

(儿子永远是儿子,爹还是你爹)

  1. 子类的方法不能缩小父类方法的访问权限

super

  • super是指向父类的引用

super可以在子类构造器中,调用父类的某个构造器

如果构造方法没有显示地调用父类的构造方法,那么编译器会自动为它加上一个默认的super()方法调 用。如果父类由没有默认的无参构造方法,编译器就会报错,super()语句必须是构造方法的第一个子 句。

super可以用来区分子父类的同名成员

如果存在同名问题,在子类中调用同名成员,默认有this.成员调用当前子类同名成员,想要调用父类同名成员, 必须定义为super.成员
public class Override02 {
    public static void main(String[] args) {
        Dog dog = new Dog();
        dog.run();//输出的是动物都会跑
    }
}
class Anima{//父类
    int eye = 2;
    public void run(){
        System.out.println("动物都会跑");
    }
}
class Dog extends Anima{//子类
    public void run(){
        super.run();//通过super.成员/方法  调用父类中成员/方法
    }
}

多态

为什么要使用多态

  • 使用传统代码的缺点:代码的复用性不高,而且不利于代码维护

解决方案:使用多态

多态的基本介绍

方法或对象具有多种形态。是面向对象的第三大特征,多态是建立在封装和继承基础之上

多态存在要有三个必要条件

  • 要有继承

  • 要发生重写

  • 父类引用指向子类对象

多态的具体体现:

方法的多态

重写和重载就体现多态

对象的多态

牢记几点:

一个对象的编译类型和运行类型可以不一致
编译类型在定义对象时,就确定了,不能改变
运行类型是可以变化的
编译类型看定义时 = 号的左边 , 运行类型看 = 号的右边
public class WdPoly {
    public static void main(String[] args) {
        //父类引用指向子类对象☆☆☆☆☆
        //编译类型是Animal  可以指向(接收)Animal子类的对象
        Animal animal = new Dog();
        //属性调用时,仍然是基类的属性。属性没有多态
        System.out.println(animal.age);
        animal.shout();//行为(方法)存在多态
    }
}
class Animal{
    public int age=10;
    public void shout(){
        System.out.println("叫了一声");
    }
}

class Dog extends Animal{
    public int age = 28;
    public void shout(){
        System.out.println("汪汪汪!");
    }
    public void bone(){
        System.out.println("我爱吃骨头和便便");
    }
}

向上转型

本质:父类的引用指向了子类的对象

语法:父类类型 引用名 = new 子类类型()

特点:编译类型看左边,运行类型看右边。可以调用父类中的所有成员(属性和方法)(需要遵守访问权限),不能调用子类特有成员;最终运行效果看子类的具体实现。

向下转型

语法:子类类型 引用名 = (子类类型)父类引用‘

只能强转父类的引用,不能强转父类的对象

要求父类的引用必须指向的是当前目标类型的对象

当向下转型后可以调用子类类型中所有的成员

Cat cat = (Cat) animal//向下转型:子类类型 引用名 =(子类类型)  父类引用

属性没有重写之说!属性的值看编译类型

public class Poly03 {
    public static void main(String[] args) {
        //属性没有重写之说!属性的值看编译类型
        Base base = new Sub();//向上转型
        System.out.println(base.count);//?  看编译类型  10
        Sub sub = new Sub();//20
    }
}
class Base { //父类
     int count = 10;
}
class Sub extends Base{//子类
    int count = 20;
}

抽象类(abstract)

当父类的一些方法不能确定时,可以用abstract关键字来修饰该方法,这个方法就是抽象方法,用abstract来修饰该类就是抽象类。

  • 当一个类中存在抽象方法时,需要将该类声明为abstract类

  • 一般来说,抽象类会被继承,有其子类来实现抽象方法

  • 抽象类的价值更多作用是在于设计,是设计者设计好后,让子类继承并实现抽象类。在框架和设计模式使用较多。

 abstract class Animal{
    private String name;

     public Animal(String name) {
         this.name = name;
     }
     //思考:这里的eat 你实现了,其实没有什么意义
     //即:  父类方法不确定性的问题
     // =====>考虑将该方法设计为  抽象方法
     //=====>所谓抽象方法就是没有实现方法
     //=====>所谓没有实现就是指   没有方法体
//     public void eat(){
//         System.out.println("这是一个动物,但是不知道吃什么");
//     }

     //当一个类中存在抽象方法时,需要将该类声明为abstract类
     //一般来说,抽象类会被继承,有其子类来实现抽象方法
     public abstract void eat();

 }

抽象类细节:

  • 抽象类不能被实例化(不能有对象,你都抽了它了)

public class abstract02 {
    new animal();//报错
}
abstract class animal{
    abstract void show();
}
  • 抽象类不一定要包括abstract方法。也就是说,抽象类可以没有abstract方法,但可以有实现方法。

  • 有abstract方法,这个类就一定要声明为abstract类

abstract class animal{
    //这是实现的方法
    public void show(){
        System.out.println("滚犊子");
    }
}
  • abstract 只能修饰类和方法,不能修饰属性和其它的

class C {
    public abstract int n1 = 1;//会报错
}
  • 抽象类可以有任意成员【抽象类还是类】,比如说,非抽象(实现)方法、构造器、静态属性等等

class D{
    public int n1 = 1;
    public static String name = "小甘";
    public void hi(){
        System.out.println("hi");
    }
}
  • 抽象方法不能有主体{ } ,既不能实现

  • 如果一个类继承了抽象类,则它必须实现抽象类的所有抽象方法,除非它自己也声明为abstract类(有点霸道哦)

abstract class E{
    public abstract void hi();
}
abstract class F extends E{
    //要么自己也声明成abstract类
}
class G extends E{
    public void hi(){//要么实现父类E的抽象方法(发生了重写),所谓实现方法,就是有方法体
    }
}
  • 抽象方法不能使用privatefinal、static关键字修饰,因为这些关键字都是和重写相违背的。

final:被final修饰的类不能有子类,方法就不能重写,但abstract必须要有子类,且必须发生重写
static:被static修饰的方法可以通过类名调用,但abstract必须通过子类实现。
private:被private修饰的方法不能重写,但abstract必须要重写

接口(interface)

为什么要有接口:现实中的例子就是 type-c接口。

中心观点;接口是希望有别的类来实现它的

package HomeWork.interface01;

import org.w3c.dom.ls.LSOutput;

public class interface01 {
    public static void main(String[] args) {
        //创建手机,相机对象
        Phone phone = new Phone();
        Camera camera = new Camera();
        //创建电脑
        Computer computer = new Computer();
        computer.work(phone);//把手机接入到电脑
        System.out.println("=============");
        computer.work(camera);

    }
}

 interface Usb{
    //规定接口的相关方法,自己规定的,
    public void start();
     public void stop();
}

//Phone 实现  Usb 接口
//解读: 即Phone类需要实现 UsbInterface接口,就是把接口的方法实现了
class Phone implements Usb{
    @Override
    public void start() {
        System.out.println("手机开始工作了....");
    }
    @Override
    public void stop() {
        System.out.println("手机停止工作了...");
    }
}

//实现接口
class Camera implements  Usb{
    @Override
    public void start() {
        System.out.println("相机开始工作了...");
    }
    @Override
    public void stop() {
        System.out.println("相机停止工作了...");
    }
}

class Computer{
    //编写方法来接入接口
    public void work(Usb usbInterface){
        //通过接口  来调用方法
        usbInterface.start();
        usbInterface.stop();
    }
}

基本介绍:

interface和class是同一级别的人物

接口就是给出一些没有实现的方法(即抽象类方法),封装到一起,到某类要是用的时候,在根据具体情况把这些方法写出来(一般是重写)

语法:implement(实施)

interface 接口名{
	//属性
	//方法(1.抽象方法 2.默认实现方法  3.静态方法)
    //在接口中,抽象方法 ,可以省略abstract关键字
}
class 类名 implement 接口{
	自己的属性
	自己的方法
	必须实现的接口的抽象方法(有点类似抽象类介绍的那样)
}

小结:

  1. 在jdk7.0前,接口里的所有方法都没有方法体(8.0就可以有了),即都是抽象对象

  1. jdk8.0后,接口可以有静态方法、默认方法,也就是说接口中可以有方法的具体实现。

注意事项和细节

  • 接口不能被实例化

  • 接口中所有的方法是 public方法,可以不用abstract修饰

  • 一个普通类实现接口,就必须将该接口的所有方法都实现(霸道总裁又出现了) alt+enter 快捷键

interface A1{
    void say();//第一个
    void hi();//第二个
}
class B1 implements A1{
    @Override
    public void say() {
        System.out.println("好霸道");
    }
    @Override
    public void hi() {
        System.out.println("我喜欢");
    }
}
  • 抽象类实现接口时,可以不用实现接口的方法(抽象类比霸道总裁更霸道)

  • 一个类同时可以实现多个接口

interface G1{}//接口1
interface G2{}//接口2
//一个类可以实现多个接口
class Dog implements G1,G2{}//Dog类可以实现两个接口
  • 接口中的属性,只能是final的,而且是pubilc static final 修饰符。比如:int a = 1;实际是 public static final int a =1;(必须初始化)

  • 接口中属性的访问形式:接口名.属性名

  • 接口不能继承其它的类,但是可以继承多个别的接口,接口和接口之间是继承关系,接口内谈实现

interface G1{}
interface G2{}
//接口可以继承其它接口
interface G3 extends G1,G2{

}
  • 接口的修饰符,只能是public和默认,这点和类的修饰符是一样的

继承和接口的区别

接口的多态

内部类

基本概念

  • 一个类的内部又完整的嵌套了另一个类结构,被嵌套的类被称为内部类(inner class),嵌套其他类的类称为外部类 (outer class)。是我们类的第五大成员(属性、方法、构造器、代码块、内部类)。内部类最大的特点就是可以直接访问私有属性,并且可以体现类与类之间的包含关系。

基本语法

内部类的分类

  • 定义在外部类局部位置上(比如说方法内):

1、 局部内部类(有类名):局部内部类是定义在外部类的局部位置,比如说方法中,并且有类名。

1.1、可以直接访问外部类的所有成员,包含私有的。
1.2、不能添加访问修饰符,因为它的地位就是一个局部变量。局部变量是不能使用修饰符的,但可以使用final修饰,因为局部变量也可以使用final。
1.3、作用域:仅仅在定义它的 方法或代码块
1.4、局部内部类----访问-----外部类的成员【访问方式:直接访问】
1.5、访问方式:创建对象,在访问(注意:必须在作用域内) 即——>外部类在方法中,可以创建Inner02对象,然后调用方法即可
1.6、外部其他类---不能访问--->局部内部类(因为 局部内部类地位是一个局部变量)
1.7、如果外部类和局部内部类的成员重名时,默认遵循就近原则,如果想访问外部类的成员,则可以使用(外部类名.this.成员)去访问
//演示局部内部类的使用
public class LocalInnerClass {
    public static void main(String[] args) {

    }
}

class Outer02{//外部类
    private  int n1 = 100;
    private void m2(){} //私有方法
    public void m1(){//方法
        //1.局部内部类是定义在外部类的局部位置,通常在方法中
        //3.不能添加访问修饰符,但是可以使用final修饰
        //4.作用域:仅仅在定义它的方法中或代码块中
        class Inner02{//局部内部类(本质上也仍然是个类,类该有的它都有)
            //2.可以直接访问外部类的所有成员,包括私有的。
            public void f1(){
                //5.局部内部类可以直接访问外部类的所有成员,包括私有的
                System.out.println("n1 =  "+n1);
                m2();//私有方法同样可以访问。
            }
        }
        //6.外部类在方法中,可以创建Inner02对象,然后调用方法即可
        Inner02 inner02 = new Inner02();
        inner02.f1();
    }
}

记住:

1、局部内部类定义在方法中 / 代码块中
2、作用域在方法体中/代码块中
3、本质仍然是一个 类

2、匿名内部类(没有类名,重点)

  • 定义在外部类的成员位置上:

  1. 成员内部类(没用static修饰)

  1. 静态内部类(使用static修饰)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值