zoukankan      html  css  js  c++  java
  • 跟着刚哥梳理java知识点——面向对象(八)

    面向对象的核心概念对象

      类:对一类事物描述,是抽象的、概念上的定义。

      对象:实际存在的该类事物的每个个体,因而也成为实例(Instance)。

    Java类及类的成员属性(成员变量Field)和方法(method)

    类对象的内存结构

    Animal a1 = new Animal();
    a1.name = "花花";
    a1.age = 3;

    之前梳理数组的时候说过,栈中的对象存放对象的引用及Animal a1的a1这个引用。堆空间都是new出的东西包括成员变量。

      ① 在栈中声明一个a1的引用变量

      ② 在堆中申请一块区域存储new Animal并为成员变量赋默认值(name=null,age=0)。

      ③ a1的引用变量指向堆的new Animal的首地址(16进制数字)。

      ④ a1.name="花花":修改成员变量name值为花花。

      ⑤ a1.age = 3:修改成员变量age值为3。

    Animal a2 = new Animal();

    每次new出来的对象都是在堆中重新申请的一个新空间

    Animal a3 = a1;
    a3.name = "草草"

    ① 在栈中声明一个a3的引用变量

    ② a3的引用变量指向a1的指向的堆空间的首地址

    ③ a3.name = "草草":修改成员变量name值为"草草"。

    最终,a1和a3的成员变量name都修改成了草草。

    类的== 和equals

     == 表示对象引用的地址是否相等,即16位的首地址码是否一致。

       类没有重写equals,所以用的是Object的equals的方法,看源码就能看出来,和==一样。

      想让比较的两个类所有属性值都一样的情况下就相等的话,需要自己重写equals方法。

    类的成员之一:属性

    成员变量(属性)和局部变量

    1、修饰符

      ① 成员变量:public、private、protected、default、final、static

      ② 局部变量:final

      笔试题:

      public class aClass {  
        void run() {    
          static int i = 0; 
          i++;    
          System.out.println(i);
        }    
        public static void main(String args[]) {    
          aClass obj = new aClass();    
          obj.run();    
          obj.run();    
        }    
      } 

    结果为:A:0    B:1    C:2    D:编译错误

    很明显是选D,因为局部变量只能用修饰符final修饰。

    2、默认初始化值:

      ① 局部变量:类的局部变量和数组元素的默认初始化值一致的。

      ② 成员变量:没有默认值。

    3、内存中存放的位置:

      ① 局部变量:堆

      ② 成员变量:栈

      ① 在栈中声明一个p1的引用变量

      ② 在堆中申请一块区域存储new Person并为成员变量赋默认值(name=null,age=0,sex=false)。

      ③ p1的引用变量指向堆的new Person的首地址(16进制数字)。

      ④ 在栈中申请n的变量并赋值为付昊(n为形参的参数名字)

      ⑤ 将n这个局部变量的值赋值给刚才new Person的成员变量name

      ⑥ setName执行完毕后,n这个局部变量销毁。

    4、类对象的属性赋值顺序:

      ① 属性的默认值:private int age;

      ② 属性的显式赋值:private int age = 1;

      ③ 构造器给属性赋值:public Person(int a){age = a;}

      ④ 通过setter方法赋值:public void setAge(int n){age = n;}

     类的成员之二:方法

    1、修饰符:private、protect、public、static、final、synchronize。

    2、重载:方法名字相同,参数列表不同(参数个数不同和类型不同)。

    3、重写:继承中子类重新实现了父类的方法。

      ① 要求子类方法名字和参数列表完全和父类一样。

      ② 子类方法的修饰符不能小于父类方法的修饰符。

    4、形参:

    java中的参数传递机制:值传递

      ① 基本数据类型传递(传递的值是具体的实参的基本数据类型的值)

    public class TestArgsTransfer {
        public void swap(int i,int j){
            int temp = i;
            i = j;
            j = temp;
        }
        public static void main(String[] args){
            TestArgsTransfer tt = new TestArgsTransfer();
            int i = 10;
            int j = 5;
            tt.swap(i,j);
        }
    }

     内存结构

      ② 引用数据类型传递(传递的值是引用对象的16位的首地址值)

    public class TestArgsTransfer {
        public void swap(DataSwap d){
            int temp = d.i;
            d.i = d.j;
            d.j = temp;
        }
        public static void main(String[] args){
            TestArgsTransfer tt = new TestArgsTransfer();
            DataSwap ds = new DataSwap();
            tt.swap(ds);
        }
    }
    class DataSwap{
        int i = 10;
        int j = 5;
    }

    类的成员之三:构造器:

    特点:

      ① 和类名字一致

      ② 没有返回值

      ③ 只能被4个访问权限修饰符修饰

    作用:

      ① 创建对象

      ② 给创建的对象的属性赋值,通过构造器的形参实现。

    【知识点】:

      ① 若不显式的声明类的构造器的话,程序会默认的提供一个空参的构造器。

      ② 若显式的声明的类的构造器的话,那么默认的构造器就不再提供。

      ③ 类的多个构造器之间形成重载。

    java封装性:

    1、将属性私有化,然后通过调用getter和setter方法来获取或者设置属性。

      为什么不直接使用对象.属性直接使用属性呢?

      设想,你有一个Person类代表一个人,Person有一个char类型的sex字段表示性别,理论上,sex只接受两个值, 'M '和 'F ',但如果你把sex字段设为public,

      你很难限制你的用户只给它赋 'M '或 'F '值。将sex设为private,再用setSex()来设置性别,你就完全可以控制这种行为了。而且你还可以控制只能get不能set,

      或相反,但如果是public就不行了。另外我们可能并不想对属性进行写操作,这个时候,可以直接不写set方法。这就是只读属性了。

    2、通过4种访问权限修饰符隐藏了类或者方法

    java继承性:extends

    1、子类继承父类后,父类中声明的属性、方法,子类就可以获取到。

    2、子类除了通过继承,获取父类的结构之外,还可以定义自己特有的成分。

    3、java中的类只支持单继承,不支持多继承。

    4、由于Object是所有类的超类,那么你在最顶层的父类其实还会调用Object的无参构造函数。

    子类对象实例化的全过程

     1 public class Main {
     2     public static void main(String[] args) {
     3         Dog dog = new Dog();
     4         dog.setAge(10);
     5         dog.setName("花花");
     6         dog.setHostName("小明");
     7         System.out.println("age:" + dog.getAge() + "
    name:" + dog.getName() + "
    hostname:" + dog.getHostName());
     8     }
     9 }
    10 //生物
    11 class Creator{
    12     private int age;
    13     public int getAge() {
    14         return age;
    15     }
    16     public void setAge(int age) {
    17         this.age = age;
    18     }
    19 }
    20 //动物
    21 class Animal extends Creator{
    22     private String name;
    23     public String getName() {
    24         return name;
    25     }
    26     public void setName(String name) {
    27         this.name = name;
    28     }
    29 }
    30 //
    31 class Dog extends Animal{
    32     private String hostName;
    33     public String getHostName() {
    34         return hostName;
    35     }
    36     public void setHostName(String hostName) {
    37         this.hostName = hostName;
    38     }
    39 }

    子类对象的实例化并没有在堆中创建了任何它的父类对象,只是把父类对象的属性带了过来。

     java多态性

    多态性:可以理解为一个事物的多种表现形态。

    1、方法的重载与重写
      同一类中方法名相同,但是调用子类和父类的表现却是不同的。

    2、子类对象的多态性

    Person p = new Student(); //子类对象的多态性,父类的引用指向子类对象
    //虚拟方法调用:实际调用子类重写父类的方法,但是父类必须有此方法声明
    p.eat();
    p.walk();

    3、向下转型和向上转型

    Person p = new Student();//向上转型
    Student s = (Student)p;//向下转型,强制类型转换

      但是这种转型是有一些风险的,那么最好用instanceof来判断

    4、子类对象的多态性,并不适用属性。加入父类和子类的属性值相同,左边是谁,就使用谁的属性。

    匿名类对象:

    1、创建类的对象是没有名字的。

    2、使用场景:当我们只需要调用一次类的对象时。

    3、特点:创建的对象调用完一次这个对象就销毁了。

    new Person().getName;

    关键字:

    1、this

    this表示当前对象,用来修饰属性、方法、构造器

    在构造器内部,this必须声明在首行。

    class Cake{
        private String name;
        public Cake(){
            System.out.println("cake");
        }
        public Cake(String name){
            this();//this调用无参的构造器
            this.name = name;//this调用当前对象
        }
    }

    2、super

    this表示父类对象,用来修饰属性、方法、构造器

    在构造器内部,supper必须声明在首行。

    在构造器内部,子类构造器都默认第一步调用父类无参的构造器,除非你加了this,因为只要加了this的话super就不起作用了。

     1 class Person{
     2     public Person(){
     3         System.out.println("p1");
     4     }
     5     public Person(int id,String name){
     6         this();
     7         System.out.println("p2");
     8     }
     9 }
    10 class Student extends Person{
    11     public Student(){
    12         System.out.println("s1");
    13     }
    14     public Student(String n){
    15         System.out.println("s2");
    16     }
    17     public Student(int g){
    18         this("s");
    19         System.out.println("s3");
    20     }
    21 }
    22 public class Main {
    23     public static void main(String[] args){
    24         Student student = new Student(0);
    25     }
    26 }

    输出结果:p1 s1 s2

     总结:

      ① 在构造器内要么用this要么用super,用了this,super就会失效。

      ② 在构造器内如果子类不显式的调用父类的构造器,那么默认调用无参的super();

      ③ 设计父类的时候,如果不显式的声明一个无参的构造函数,那么有可能造成程序编译错误。

    3、static

    静态的,可以修饰属性、方法、代码块、内部类

    1)属性(类变量):

    class SportsMan {  
        String name;  
        int age;  
        static String nation;   
        public SportsMan(String name, int age) {  
            super();  
            this.name = name;  
            this.age = age;  
        }
    }

      

    总结:

      ① SportsMan类中的nation属性是static修饰的,由这个类创建的对象都共用这个属性。 

      ② 类变量的加载早于对象,所以既可以用“sp1.nation”,也可以用“SportsMan.nation”调。 

      ③ 当其中一个对象对此类变量进行修改,会影响其他对象的类变量的一个调用。 

        

    2)方法:

      ① 随着类的加载而加载,在内存中也是独一份。

      ② 可以直接通过“类.类方法”

      ③ 静态方法内部可以调用静态的属性或者方法,但是不能调用非静态的属性和方法,因为静态的生命周期要早于非静态对象。

      ④ 非静态的方法可以调用静态的属性和方法,因为非静态的方法晚于静态的方法和属性。

    4、final

      ① 修饰类 :不能被继承

      ② 修饰方法:不能被重写

      ③ 修饰属性:此属性就是一个常量。此常量不能使用默认初始化(除非在构造器中或者非静态代码块初始化),可以显式的赋值。

    1     final int I;// 编译错误
    2     final int I = 12;//正确
    3     public void m(){
    4         I = 15; // 编译错误
    5     }

      但是如果放在构造器中,就没问题。

    1     final int I;//正确
    2     public A(){
    3         I = 15;//正确
    4         System.out.println("3");
    5     }

    笔试题一:

    1 public class Something{
    2   public int addOne(final int x){
    3     return ++x;
    4   }
    5 }

      肯定编译错误,final一旦修饰的时候赋了值,那么对不起,我的值就是最终的值,以后谁都不能改,谁改谁错。

     笔试题二:

     1 public class Something{
     2   public static void main(String[] args){
     3     Other o = new Other();
     4     new Something.addOne(o);
     5   }
     6   public void addOne(final Ohter o){
     7     o.i++
     8   }
     9 }
    10 class Other{
    11   public int i;
    12 }

      肯定不出错,final修饰的是o(即o的堆地址),o里的属性没关系,想怎么变就怎么变。

    类的成员之四:初始化块

    1)非静态块

     1 class Person{
     2     int id = 0;
     3     String name = "n";
     4     {
     5         id = 10;
     6         name = "ni";
     7         System.out.println("你好:你");
     8     }
     9     {
    10         id = 11;
    11         name = "hao";
    12         System.out.println("你好:好");
    13     }
    14     public Person(){
    15         id = 12;
    16         name = "ni hao";
    17     }
    18 }
    19 public class Main {
    20     public static void main(String[] args) {
    21         Person p1 = new Person();
    22         System.out.println(p1.id + "
    " + p1.name);
    23     }
    24 }

    输出结果:

      你好:你
      你好:好
      12
      ni hao

    ① 可有对类的属性(静态和非静态)进行初始化操作

    ② 里面可以有输出语句

    ③ 属性赋值的顺序:默认初始化值--->显式初始化或者代码块初始化(此处看顺序位置)--->构造器--->通过setter方法

    2)静态块

    ① 随着类的加载而加载,而且只被加载一次。

    ② 静态的代码块在非静态代码块之前运行

    ③ 非静态的属性不能放在静态代码块

     笔试题:

     1 class A{
     2     static {
     3         System.out.println("1");
     4     }
     5     {
     6         System.out.println("2");
     7     }
     8     public A(){
     9         System.out.println("3");
    10     }
    11 }
    12 class B extends A{
    13     static {
    14         System.out.println("a");
    15     }
    16     {
    17         System.out.println("b");
    18     }
    19     public B(){
    20         System.out.println("c");
    21     }
    22 }
    23 public class Main {
    24     public static void main(String[] args) {
    25         A a = new B();
    26         a = new A();
    27     }
    28 }

    输出结果:1 a 2 3

    总结:

      ① 不管是静态代码块还是非静态代码块都是从父类开始执行的。

      ② 静态代码块只执行一次,非静态代码块new一次执行一次。

    抽象类:

    1、抽象类

      ① 抽象类不能被实例化

      ② 抽象类可以有构造函数 

      ③ 抽象方法所在的类一定是抽象类

      ④ 抽象类中可以没有抽象方法

      ⑤ 不能和final共同修饰类

    2、抽象方法

      ① 抽象方法必须需要子类进行重写

      ② 抽象类中可以有具体的实现方法。

      ③ 若子类是一个具体的“实体类”,那么就必须实现继承抽象类中的所有的抽象方法

      ④ 若子类继承抽象类,没有重写完所有的抽象方法,那么此类必须也是一个抽象类

    3、其他:abstract不能修饰属性、构造器、private、final、static

      ① abstract 不能修饰属性,因为子类的属性是无法重写父类属性的

      ② abstract 不能修饰构造器,因为构造器不能被重写

      ③ abctract 不能和private修饰,因为你本来就是想让子类进行重写的,private的话你还让子类怎么重写。

      ④ final就不用说了,它修饰的方法不能被重写。它两个本身就是矛盾的。

      ⑤ static的话,直接用类.方法调用时不合规的。

     1 abstract class Animal {
     2     public Animal(){
     3         // 只要实例化子类,抽象类的构造器会被执行。
     4         System.out.println("我是一个抽象动物");
     5     }
     6     public void breath(){
     7         //抽象类中可以有具体实现方法。可以通过实例化子类,再调用抽象类的方法。
     8         System.out.println("动物都会呼吸");
     9     }
    10     public abstract void cry();
    11 }
    12 
    13 class Cat extends Animal{
    14 
    15     @Override
    16     public void cry() {
    17         System.out.println("猫叫:喵喵...");
    18     }
    19 }
    20 
    21 class Dog extends Animal{
    22 
    23     @Override
    24     public void cry() {
    25         System.out.println("狗叫:汪汪...");
    26     }
    27 
    28 }
    29 public class Main {
    30     public static void main(String[] args) {
    31         Animal cat = new Cat();
    32         cat.cry();
    33     }
    34 }

     执行结果:

      我是一个抽象动物
      猫叫:喵喵...

     接口

     接口是一个特殊的抽象类,只有两个元素①常量 ②抽象方法

     1、接口不需要写权限修饰符,肯定是public。

       2、常量默认使用public static final修饰,方法默认使用public abstract修饰

     3、接口既不能实例化,也不能有构造器

     4、如果实现接口,那么就需要实现接口的所有抽象方法

     5、接口之间可以多继承

     6、类可以实现多个接口,但是需要实现这些接口所有的抽象方法。

     1 public class DayStudy {
     2     public static void main(String[] args) {
     3         //1、第一个多态性。格式:接口 参数 = new 实现类()
     4         Runner d = new Duck();
     5         test1(d);
     6         //2、第二个多态性。参数用接口类型,传入实现类,解耦
     7         Duck d1 = new Duck();
     8         test1(d1);
     9         test2(d1);
    10         test3(d1);
    11     }
    12     public static void test1(Runner r ){
    13         r.run();
    14     }
    15     public static void test2(Swiner s ) {
    16         s.swin();
    17     }
    18     public static void test3(Flier f ) {
    19         f.fly();
    20     }
    21 }
    22 interface Runner{
    23     void run();
    24 }
    25 interface Swiner{
    26     void swin();
    27 }
    28 interface Flier{
    29     void fly();
    30 }
    31 class Duck implements Runner,Swiner,Flier{
    32     @Override
    33     public void run() {
    34         System.out.println("会跑");
    35     }
    36     @Override
    37     public void swin() {
    38         System.out.println("会下水游泳");
    39     }
    40     @Override
    41     public void fly() {
    42         System.out.println("会飞");
    43     }
    44 }
    接口匿名类 :接口 参数 = new 接口(){ 这里面具体把接口的抽象类实现 }
    Runner r = new Runner(){
      @override
      public void run(){
        system.out.printLn("匿名类");
      }
    }
  • 相关阅读:
    CSS——如何清除浮动
    CSS——display(Block none inline等)属性的用法
    css3——position定位详解
    [转载]mysql创建临时表,将查询结果插入已有表中
    [转载]基于LVS的AAA负载均衡架构实践
    Percona Toolkit 2.2.19 is now available
    [转载]使用awk进行数字计算,保留指定位小数
    [转载]github在线更改mysql表结构工具gh-ost
    [转载]binlog归档
    [转载]MySQL运行状态show status详解
  • 原文地址:https://www.cnblogs.com/hzg110/p/6557674.html
Copyright © 2011-2022 走看看