类和对象

类的概念

类是一个模板,是抽象的概念集合,它描述一类对象的行为和状态

  • 种类、类别.....(我们人为对相同类似的事务和东西的归类)定义为类,即所有类的父类总归为Object(最终类,我们自定义的类默认继承Object),Java对所有类的概括

  • 如动物类,动物下又可分哺乳动物和卵生动物,牛、兔、虎、蛇......每一个又可以单独归为一个类,每个动物下还有不懂种类

  • 不同类有不同属性(变量)和行为(方法),

    属性:长度,重量,年龄等

    行为:吃,跑,叫

定义

/*	访问修饰符 class(关键字) 类名 { }
	类名 约定采取驼峰命名法,首字母大写
*/

类中有啥

属性

  1. 实例变量:上面的变量就为实例变量,他们与对象挂钩,是需要通过对象来调用的,或者是本类,子类方法,代码块中调用(用于声明对象的结构的, 在创建对象时候分配内存,每个对象有一份!也有默认值
  2. 局部变量::在栈中分配,作用于方法或语句中,必须初始化,有值才能运算
  3. 静态变量 static int count; 在这打比可以描述该运行中dog的个数记录
    • 一声明就被存储在栈中,直接占据内存,可以快速稳定的调用
    • 全局唯一,在一个运行环境中,静态变量只有一个值,任何一次修改都是全局性的影响
    • 不需要new出对象引用来调用,在其他类中可以直接用-->类名.变量名调用
  4. final 常量 fianl String shape; (体型)
  5. static final String shape 静态常量

行为(方法)

不同类具有不同的方法,对该类的行为操作,完成一个动作,这个类的一个功能

静态方法与非静态方法

静态方法与静态成员变量一样,属于类本身,在类装载的时候被装载到内存,不自动进行销毁,会一直存在于内存中,直到JVM关闭。(静态方法是共享代码段,静态变量是共享数据段。既然是“共享”就有并发的问题。)

非静态方法又叫实例化方法,属于实例对象,实例化后才会分配内存,必须通过类的实例(new的对象)来引用。不会常驻内存,当实例对象被JVM回收之后,也跟着消失。

  • 非静态方法可以访问类中的任何成员,静态方法只能访问类中的静态成员
  • static内部只能出现static变量和其他static方法!而且static方法中还不能使用this关键字(this是指向当前实例对象的引用)

方法的重载

在一个类中定义多个同名的方法,要求每个方法具有不同的参数的类型或参数的个数

调用重载方法时,Java编译器能通过检查调用的方法的参数类型和个数选择一个恰当的方法。

(就是在类中可以创建多个方法,它们可以有相同的名字,但必须具有不同的参数,即或者是参数的个数不同,或者是参数的类型不同。调用方法时通过传递给它们的不同个数和类型的参数,以及传入参数的顺序来决定具体使用哪个方法。)

还记得String中的valueOf()方法嘛?

构造器

它是一个与类同名的方法,对象的创建就是通过构造器(也叫构造方法)来完成,其功能主要是完成对象的初始化。

IDEA中 按快捷键 Alt+Insert点其中的 Construtor 选择参数点Ok就会自动生成

  • 构造方法也可以被重载

代码块

一次运行中对对类,或实例化对象可以做一些初始化操作

public class Main {
    public static void main(String[] args) {
        new Text();
    }
}
class Text{
    {	//每次 实例化类(new)都会执行一次
        System.out.println("这就是构造代码块");
    }
    static { //在运行中 优先执行static静态代码块(但在一次运行中只会执行一次) 
        System.out.println("这个是静态代码块");
    }
}

对象

何谓对象?

在Java中有一句比较流行的话,叫做 "万物皆对象",这是Java语言设计之初的理念之一。

  简而言之,它就是类的实例,比如所有的应用软件中有账号这个东西,即是一个用户,还有用户信息等,这里把用户整体看成一个类(通有的模板),而具体到每个用户,比如张三这个用户,他的账号,密码,出生年月,身份证号不同,那每对于不同人就才用不同的对象来标识这个用户,而这个用户就是用户类的一个实例,一个对象。

优点:易维护、易复用、易扩展,由于面向对象有抽象封装继承多态性的特性,可以设计出低耦合的系统,使系统更加灵活、更加易于维护

缺点:性能比面向过程低

怎样创建对象

封装

封装的意义,在于明确标识出允许外部使用的所有成员函数和数据项,内部细节对外调用透明,外部调用无需修改或者关心内部实现

Get、Set方法

封装:将数据封装到类的内部,将算法封装到方法中。
封装原则:将不需要对外提供的内容都隐藏起来,把属性都隐藏,提供公共方法对
其访问,通常有两种访问方式: set 设置, get 获取。

(比如一个功能,使用时只要实现了功能就好,不需要具体了解那么做到的!

​ 当然,你也可以学会该功能实现步骤,自己也用这个挣点钱话)

作用:

  • 保护数据(该变量的读写,灵活,并发考虑等)

    private 访问权限符 是私有的,只有本类中可以访问,那没对于其他类来说,可以考虑只写一个get(对于类中的属性只读)

    public class Woman{//女人
        private int age;//年龄
    	private boolean sex;//性别 false代表女 true代表男
        //实例化一个对象,就只针对这一个人,身份证上一般来说性别要变不?
        //所以可以对性别私有,一经构造初始化就不可更改,就就设置一个get仅供查看
        public boolean getSex(){
         	return sex;   
        }
        //而年龄对于我们来说,随着时间,每一年,年龄长一岁,可以更改
        public void setAge(int age){
            this.age = age;
        }
    }
    
  • set(赋值),get(取值)时,都可以在方法中实现一些处理判断之类的代码等操作

    //依旧是年龄
    public class Woman{
        private int age;//年龄
        public void setAge(int age)  throws Exception {
            //判断一下传入的age
            if (age > 0 && age < 150){
            	this.age = age;
            } else {
                this.age = 18;
                //这里可以设置一个恒定年龄,也可以像下方抛出一个异常
                //throw new Exception("年龄超出范围"); 
            }
        }
        @Override
        public String toString() {
            return "Woman{" +
                    "age=" + age +
                    '}';
        }
    }
    
    public class Test {
        //对上方的一个测试,如果抛出异常,暂时可以不了解,学了就懂了
        //(反正就是程序的操作不符合我们的要求,到达了意料之内的错误,就抛出这个错误)
        public static void main(String[] args) {
            Woman woman = new Woman();
            try {
                woman.setAge(160);//如果抛出异常后面打印不会执行
                /* 上面重写了Object(最终父类)的toString,
                可以在打印对象是自动调用new的类的toString()方法返回一个String字符串,
                在控制台看到该对象的具体内容,如果没有重写,那么就打印的引用地址 */
                System.out.println(woman);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    

继承

概念

继承在语法方面的好处:子类共享了父类的属性和方法的定义,子类复用了父类的属性和方法,节省了代码,做出自己的改变或扩展自的个性化

(编程思想嘛)

  • 继承只能是单继承(人之间的关系,每个人只有一个亲生爸爸)
  • 父类不能强转成子类,会造成异常!子类向父类转化是隐式的
  • final 修饰的类:不能再继承
  • final 修饰的方法:不能再重写

重写

重写是子类对父类的允许访问的方法的实现过程进行重新编写

  • 形参都不能改变,参数列表必须完全相同
  • 返回类型与被重写方法的返回类型可以不相同,但是必须是父类返回值类型的子类
  • 访问权限修饰符权限不能更低
  • 声明为 static 的方法不能被重写
  • 基于 方法的权限修饰符 和 final 确定是否可以重写
  • 重写的方法能够抛出任何非强制异常,无论被重写的方法是否抛出异常。但是,重写的方法不能抛出新的强制性异常,或者比被重写方法声明的更广泛的强制性异常,反之则可以。

重写的好处在于子类可以根据需要,定义特定于自己的行为

(每个人都有自己不一样的际遇)

super() 、super .和this() 、this .

  • super() :调用父类无参构造器,一定在子类构造器第一行使用!如果没有则是默认存在super()的!这是Java默认添加的super()
  • super. :是访问父类对象,父类对象的引用,与this.用法一致 (父类中被重写的方法,则必须使用关键字 super)
  • this() :调用本类的其他构造器,按照参数调用构造器,必须在构造器中使用,必须在第一行使用, this() 与super() 互斥,不能同时存在
  • this. :是访问当前对象,本类对象的引用,在能区别实例变量和局部变量时, this 可省略,否则一定不能省

使用supre.时注意父类定义的访问权限修饰符

抽象类

如果一个类中没有包含足够的信息来描绘一个具体的对象,这样的类就是抽象类。

  • 抽象类不能被实例化,如果被实例化,就会报错,编译无法通过。只有抽象类的非抽象子类可以创建对象。
  • 抽象类中不一定包含抽象方法,但是有抽象方法的类必定是抽象类。
  • 抽象类中的抽象方法只是声明,不包含方法体,就是不给出方法的具体实现也就是方法的具体功能。
  • 构造方法,类方法(用 static 修饰的方法)不能声明为抽象方法。
  • 抽象类的子类必须给出抽象类中的抽象方法的具体实现,除非该子类也是抽象类。

在Java中抽象类表示的是一种继承关系,一个类只能继承一个抽象类,而一个类却可以实现多个接口。

抽象方法

如果你想设计这样一个类,该类包含一个特别的成员方法,该方法的具体实现由它的子类确定,那么你可以在父类中声明该方法为抽象方法。

Abstract 关键字同样可以用来声明抽象方法,抽象方法只包含一个方法名,而没有方法体。

抽象方法没有定义,方法名后面直接跟一个分号,而不是花括号。

  • 如果一个类包含抽象方法,那么该类必须是抽象类。
  • 任何子类必须重写父类的抽象方法,或者声明自身为抽象类。(否则,该子类也必须声明为抽象类)
  • 最终,必须有子类实现该抽象方法,否则,从最初的父类到最终的子类都不能用来实例化对象。

接口

接口无法被实例化,但是可以被实现

接口与类相似点:

  • 一个接口可以有多个方法。
  • 接口文件保存在 .java 结尾的文件中,文件名使用接口名。
  • 接口的字节码文件保存在 .class 结尾的文件中。
  • 接口相应的字节码文件必须在与包名称相匹配的目录结构中。

接口与类的区别:

  • 接口不能用于实例化对象。
  • 接口没有构造方法。
  • 接口中所有的方法必须是抽象方法。JDK 1.8 以后,接口里可以有静态方法和方法体了。
  • 接口不能包含成员变量,除了 static 和 final 变量。
  • 接口不是被类继承了,而是要被类实现。
  • 接口支持多继承。

接口特性

  • 接口中每一个方法也是隐式抽象的,接口中的方法会被隐式的指定为 public abstract(只能是 public abstract,其他修饰符都会报错)。
  • 接口中可以含有变量,但是接口中的变量会被隐式的指定为 public static final 变量(并且只能是 public,用 private 修饰会报编译错误)。
  • 接口中的方法是不能在接口中实现的,只能由实现接口的类来实现接口中的方法。

抽象类和接口的区别

  • 抽象类中的方法可以有方法体,就是能实现方法的具体功能,但是接口中的方法不行。
  • 抽象类中的成员变量可以是各种类型的,而接口中的成员变量只能是 public static final 类型的。
  • 接口中不能含有静态代码块以及静态方法(用 static 修饰的方法),而抽象类是可以有静态代码块和静态方法。
  • 一个类只能继承一个抽象类,而一个类却可以实现多个接口。

多态

多态是同一个行为具有多个不同表现形式或形态的能力。

多态就是同一个接口,使用不同的实例而执行不同操作,

多态性是对象多种表现形式的体现。

多态的优点

  • 消除类型之间的耦合关系
  • 可替换性
  • 可扩充性
  • 接口性
  • 灵活性
  • 简化性

多态存在的三个必要条件

  • 继承
  • 重写
  • 父类引用指向子类对象:Parent p = new Child();

多态的实现方式

  1. 重写
  2. 接口
  3. 抽象类和抽象方法

执行顺序

  1. 首先要看是从那运行程序的(就是main方法开始运行起走)(但不会直接加载main中语句)
  2. 先找该类的父类(最终父类)的静态变量, 静态代码块,其中加载顺序是按照类中书写的先后顺序加载的 ( 静态代码块在类被加载的时候就运行了,而且只运行一次,并且优先于各种代码块以及构造函数)
  3. 自身的静态变量, 静态代码块(至于自身的子类和父类的其子类 表示 我咋知道有他们?)
  4. (如果main方法里啥都没有,大概只会加载这些了) 如果main方法里语句,那么按照顺序执行
  5. 语句中 实例化类时(创建对象) 根据这个类来判断,如果该类的父类(从顶到下)的静态变量和静态代码块被执行过就不会在执行了,没有执行过的会依次执行,也是按照顺序执行
  6. 然后再是所创建对象的全局变量(类的属性,方法中的局部变量在调用方法时才会加载)和构造代码块(每次实例化类(new)都会执行一次)
  • 初始

    public class Main extends FatherMain{
        static int a = 10;
        static {
            System.out.println("static : Main");
        }
        {
            System.out.println("main");
        }
        public static void main(String[] args) {
        }
    }
    
    class FatherMain extends GrandpaMain{
        static int i = 10;
        static {
            i = 20;
            System.out.println("static : FatherMain");
        }
        {
           System.out.println("fatherMain");
        }
    }
    class GrandpaMain{
        static {
            System.out.println("static : GrandpaMain");
        }
        {
            System.out.println("grandpaMain");
        }
    }
    

    单纯运行上面的main方法(其中啥也没有时)(静态变量也赋值也运行了,只是没打印看,i=20,a=10)

    static : GrandpaMain
    static : FatherMain
    static : Main
    
  • 对于上面Main类,再main方法中 创建Main的实例

    public static void main(String[] args) {
        Main main = new Main();
    }
    

    结果(构造代码块是和对象挂钩的)

    static : GrandpaMain
    static : FatherMain
    static : Main
    grandpaMain
    fatherMain
    main
    
  • 再新增一个Test类

    public class Test extends FatherTest{
        static {
            System.out.println("static : Test");
        }
        {
            System.out.println("test");
        }
    }
    class FatherTest{
    
        static {
            System.out.println("static : FatherTest");
        }
        {
            System.out.println("fatherTest");
        }
    }
    

    更改Main类中的main方法,在新创建一个Test实例

    public static void main(String[] args) {
        System.out.println("new Main之前 ---------");
        Main main = new Main();
        System.out.println("new Main之后 ---------");
        System.out.println("new Test之前 ---------");
        Test t = new Test();
        System.out.println("new Test之后 ---------");
    }
    

    结果:(结合上面顺序来看,再自己多多测试)

    static : GrandpaMain
    static : FatherMain
    static : Main
    new Main之前 ---------
    grandpaMain
    fatherMain
    main
    new Main之后 ---------
    new Test之前 ---------
    static : FatherTest
    static : Test
    fatherTest
    test
    new Test之后 ---------
    
posted @ 2021-06-15 11:01  我豪  阅读(76)  评论(0)    收藏  举报