Java自学整理2——Java面向对象

  1. 几个注意事项

    1. 成员方法不写static关键字
    2. 导包时,如果所需的类和自己在一个包下,就不用导了
    3. 成员变量不赋值,会有默认值
  2. 一个标准的类通常要拥有四个组成部分

    1. 所有的成员变量都要使用private关键字修饰
    2. 为每一个成员变量编写一对儿Getter/Setter方法
    3. 编写一个无参构造方法
    4. 编写一个全参构造方法
  3. Java的内存需要划分成5个部分

    1. Stack):存放的都是方法中的局部变量。方法的运行一定要在栈当中运行。

      1. 局部变量:方法的参数(),或者是方法体{}内部的变量。
      2. 作用域:一旦超出作用域,立刻从栈内存当中消失。
    2. Heap):凡是new出来的东西,都在堆中。

      1. 堆内存里面的东西,都有一个地址,16进制表示的

      2. 堆内存里面的数据,都有默认值。规则:

        类型默认值
        整数0
        浮点数0.0
        字符‘\u0000’
        布尔false
        引用类型null
    3. 方法区Method Area):存储.class相关信息,包含方法的信息。

    4. 本地方法栈Native Method Stack):与操作系统相关。

    5. 寄存器pc Register):与CPU相关。

  4. 局部变量和成员变量区别总结

    1. 定义的位置不一样(重点)
      1. 局部变量:在方法内部
      2. 成员变量:在方法外部,直接写在类当中
    2. 作用范围不一样(重点)
      1. 局部变量:只有方法当中才可以使用,出了方法就不能再用
      2. 成员变量:整个类全都可以使用
    3. 默认值不一样(重点)
      1. 局部变量:没有默认值,如果要想使用,必须手动进行赋值
      2. 成员变量:如果没有赋值,会有默认值,规则和数组一样
    4. 内存位置不一样
      1. 局部变量:位于栈内存
      2. 成员变量:位于堆内存
    5. 生命周期不一样
      1. 局部变量:随着方法进栈而诞生,随着方法出栈而消失
      2. 成员变量:随着对象创建而诞生,随着对象被垃圾回收而消失
  5. 几个常用的API

    1. Scanner

      1. 除了java.lang包不用导,剩下的都要导。
      2. 键盘输入什么都是字符串,nextInt()是把字符串转为了int值。
    2. 匿名对象

      1. new Person.showName();//注:匿名对象只能使用一次。

      2. 一种使用匿名对象的输入方式

        int num = new Scanner(System.in).nextInt();
        
    3. Random

      1. nextInt()方法,返回一个int范围内的随机数。

      2. nextInt(3)方法,返回指定范围的一个随机数。(范围是[0, 3),注意右侧是开区间。)

      3. int result = nextInt(n) + 1;
        //这样可以达到取[1, n]的效果
        
    4. ArrayList

      1. 四个常用方法

        1. list.add()
        2. list.get()
        3. list.remove()
        4. list.size()
      2. 遍历集合的方法

        for(int i=0;i<list.size();i++){
            System.out.println(list.get(i));
        }
        
      3. 使用集合必须使用引用类型,不能是基本类型,为了解决这一问题,要使用包装类。

        一般包装类都是基本类型的首字母大写,有两个特殊的

        类型对应的包装类
        intInteger
        charCharacter

        jdk1.5+开始,支持自动装箱,自动拆箱:

        list.add(100);//此时,int转成Integer,是自动装箱
        int a = list.get(1);//此时,Integer转成int,是自动拆箱
        
    5. String

      1. java.lang.String类代表字符串。

        API当中说:Java程序中所有字符串字面值(如"abc")都作为此类的实例实现。

        其实就是说,程序当中所有的双引号字符串,都是String类的对象。(就算没有new,也照样是)

      2. 字符串的特点

        1. 字符串的内容永远不可变。
        2. 正因为字符串不可改变,所以字符串是可以共享使用的。
        3. 字符串效果上相当于是char[]字符数组,但是底层原理是byte[]字节数组。(新版本改的,为了节省空间,原来是用的char[]。)
      3. 创建字符串的3+1中方法

        1. public String():创建一个空白字符串,不含有任何内容
        2. public String(char[] array):根据字符数组的内容,来创建对应的字符串
        3. public String(byte[] array):根据字节数组的内容,来创建对应的字符串
        4. String str = "abc":直接创建
      4. 字符串的比较方法

        1. ==比的是地址,如果想比内容用equals(Object obj)
        2. 推荐"abc".equals(str);,因为若反之str.equals("abc");,当strnull时,会报错:NullPointerException
      5. 字符串的获取方法

        1. public int length():获取字符串当中含有的字符个数,拿到字符串的长度
        2. public String concat(String str):将当前字符串和参数字符串拼接称为新的字符串作为返回值,其本身不变
        3. public char charAt(int index):获取指定索引位置的单个字符。(索引从0开始)
        4. public int indexOf(String str):查找参数字符串在本字符串当中首次出现的索引位置,如果没有返回-1
      6. 字符串的截取

        1. public String substring(int index):截取从参数位置一直到字符串末尾,返回新字符串
        2. public String substring(int begin, int end):截取从begin开始,一直到end结束,返回中间的字符串。注:[begin, end),左闭右开。
      7. 字符串的转换

        1. public char[] toCharArray():将当前字符串拆分成字符串数组,返回。
        2. public byte[] getBytes():获取当前字符串底层的字节数组。
        3. public String replace(CharSequence oldString, CharSequence newString):将所有出现的老字符串替换成新的字符串,返回替换之后的新字符串。
      8. 字符串的分割

        public String[] split(String regex):按照参数的规则,将字符串切分成为若干部分。

        注意事项:

        1. split方法的参数其实是一个”正则表达式“。

          1. 如果按照英文句点"."进行切分,必须写"\\."(用两个反斜杠)
    6. static

      1. obj.methodStatic();通过对象调用静态方法是正确的,但是不推荐。

      2. MyClass.methodStatic();通过类来调用静态方法是正确的。

      3. 对于本类当中的静态方法,那么前面的类名称可以省略。

      4. 因为在内存中是先有的静态内容,后有的非静态,所以非静态成员方法可以访问静态和非静态,而静态方法只能访问静态(this也不行!)。

      5. 静态代码块

        1. 静态代码块格式

          public class 类名称{
              static {
                  //静态代码块的内容
              }
          }
          /*
          	特点:	1.当第一次用到本类时,静态代码块执行唯一的一次。
          		  2.静态内容总是优于非静态,所以静态代码块比构造方法先执行。
          		  3.静态代码块的典型用途:用来一次性地对静态成员变量进行赋值。
          */
          
    7. 数组工具类Arrays

      1. java.util.Arrays是一个与数组相关的工具类,里面提供了大量静态方法,用来实现数组常见的操作。
      2. public static String toString(数组):将参数数组变成字符串(按照默认格式:[元素1,元素2,元素3…])。
      3. public static void sort(数组):按照默认升序(从小到大)对数组的元素进行排序。
      4. 备注:
        1. 如果是数值,sort默认按照升序从小到大。
        2. 如果是字符串,sort默认按照字母升序。
        3. 如果是自定义类型,那么这个自定义的类需要有Comparable或者Comparator接口的支持。
        4. fori是正序遍历,forr是倒序遍历。
    8. Math

      1. java.util.Math类是数学相关的工具类,里面提供了大量的静态方法,完成与数学运算相关的操作。
      2. public static double abs(double num):获取绝对值,有多种重载
      3. public static double ceil(double num):向上取整
      4. public static double floor(double num):向下取整
      5. public static long round(double num):四舍五入
      6. Math.PI代表近似的圆周率常量
  6. 继承与多态

    1. 关系is-a

    2. 父类和子类成员变量重名,则子类优先,没有则向上找。

    3. 三种重名的变量

      public class Zi extends Fu{
          int num = 20;
          public void method(){
              int num = 30;
              System.out.println(num);//30,局部变量
              System.out.println(this.num);//20,本类成员变量
              System.out.println(super.num);//10,父类的成员变量
          }
      }
      
    4. 重载与重写

      1. 重写:方法名称和参数一样,也叫覆盖,覆写。

      2. 重载:方法名称一样,参数不一样。

      3. 方法覆盖重写的注意事项:

        1. 必须保证父子类之间方法的名称相同,参数列表相同。

          @Override写在方法前面,用来检测是不是有效的正确覆盖重写。

          这个注释就算不写,只要满足要求,也是正确的方法覆盖重写。

        2. 子类方法的返回值必须小于等于父类方法的返回值范围。

          java.lang.Object类是所有的公共最高父类(祖宗类),java.lang.String就是Object的子类。

        3. 子类方法的权限必须大于等于父类方法的权限修饰符

          public>protected>(default)>private

          注:(default)不是关键字default,而是什么都不写,留空。

    5. super关键字的3种用法

      1. 在子类的成员方法中,访问父类的成员变量
      2. 在子类的成员方法中,访问父类的成员方法
      3. 在子类的成员方法中,访问父类的构造方法
    6. this关键字的3种方法

      1. 在本来的成员方法中,访问本类的成员方法。
      2. 在本类的成员方法中,访问本类的另一个成员方法。
      3. 在本类的成员方法中,访问本类的另一个构造方法。
      4. 注意事项:
        1. this(...)调用也必须是构造方法的第一条语句,唯一一条。
        2. superthis两种构造调用,不能同时使用。
    7. Java继承的3个特点

      1. 单继承
      2. 多层继承
      3. 一个子类只能有一个父类,一个父类可以有很多个子类
  7. 抽象类

    1. //抽象类
      public abstract class Animal{
          //抽象方法
          public abstract void eat();
          //正常方法
          public void normalMethod(){
              ...
          }
      }
      
    2. 注意事项:

      1. 不能直接创建new抽象类对象。(如果创建了,调用抽象方法,没有意义。)
      2. 必须用一个子类继承抽象父类。
      3. 子类必须覆盖重写抽象父类当中的所有抽象的方法,除非这个类也是抽象类,不然就和1的情况一样了。
      4. 覆盖重写:子类去掉抽象方法的abstract关键字,然后补上方法体大括号。
      5. 创建子类对象使用。
      6. 抽象方法中可以有构造方法,供子类创建对象时,初始化父类成员使用。
      7. 抽象类中,不一定包含抽象方法,但是有抽象方法的类一定是抽象类。(不含抽象方法的抽象类通常用于某些特殊类的结构设计)
  8. 接口

    1. 接口的实现类推荐用接口名加上Impl

    2. 接口就是多个类的公共规范,是一种引用数据类型,最重要的内容就是其中的抽象方法。

    3. 接口的格式:

      public interface 接口名称{
          //接口内容
      }
      // 换成关键字interface之后,编译生成的字节码文件仍然是:.java-->.class
      
    4. 如果是Java7,那么接口中可以包含的内容有:

      1. 常量
      2. 抽象方法
    5. 如果是Java8,还可以额外包含有:

      1. 默认方法
      2. 静态方法
    6. 如果是Java9,还可以额外包含有:

      1. 私有方法
    7. 在任何版本的Java中,接口都能定义抽象方法:

      1. 格式:public abstract 返回值类型 方法名称 (参数列表);

      2. 注意事项:

        1. 接口当中的抽象方法,修饰符必须是两个固定的关键字:public abstract

        2. 这两个关键字修饰符,可以选择性地省略。

        3. 方法的三要素,可以随意定义。

        4. public interface MyInterfaceAbstract{
              //这是抽象方法
              public abstract void methodAbs1();
              //这也是抽象方法
              abstract void methodAbs2();
              //这也是抽象方法
              public void methodAbs3();
              //这也是抽象方法
              void methodAbs4();
          }
          
        5. 使用接口的步骤:

          1. 接口不能直接使用,必须有一个实现类实现该接口。

          2. 格式:

            public class 实现类名称 implements 接口名称{
                // ...
            }
            
          3. 接口的实现类必须覆盖重写(实现)接口中所有的抽象方法,去掉abstract关键字,加上方法体大括号

          4. 创建实现类对象,进行使用。

          5. 注:如果实现类并没有覆盖重写接口中的所有抽象方法,那么这个实现类自己就必须是抽象类。

          6. 接口的默认方法

            1. Java8开始,接口里允许定义默认方法。

            2. 格式:

              public default 返回值类型 方法名称(参数列表){
                  方法体
              }
              //接口中的默认方法可以解决接口的升级问题
              
            3. 接口的默认方法可以通过接口的实现类对象,直接调用。

            4. 接口的默认方法也可以被接口实现类进行覆盖重写。

          7. 接口的静态方法

            1. Java8开始,接口当中允许定义静态方法。

            2. 格式:

              public static 返回值类型 方法名称(参数列表){
                  方法体
              }
              //就是将abstract或者default换成static即可,带上方法体
              
            3. 注意事项:

              1. 不能通过接口实现类的对象来调用接口当中的静态方法。
              2. 正确用法是通过接口名称,直接调用其中的静态方法。
              3. 格式:接口名称.静态方法名(参数);
          8. 私有方法

            1. 问题描述:

              我们需要抽取一个公有方法,用来解决两个默认方法之间重复代码的问题。但是这个共有方法不应该让实现类使用,应该是私有化的。

            2. 解决方案:

              从Java9开始,接口当中允许定义私有方法。

              1. 普通私有方法,解决多个默认方法之间重复代码问题

                格式:

                private 返回值类型 方法参数(参数列表){
                    方法体
                }
                
              2. 静态私有方法,解决多个静态方法之间重复代码问题

                格式:

                private static 返回值类型 方法名称(参数列表){
                    方法体
                }
                
          9. 常量

            接口当中也可以定义“成员变量”,但是必须使用public static final三个关键字进行修饰。从效果上看,这其实就是接口的常量。

            格式:

            public static final 数据类型 常量名称 = 数据值;

            备注:

            一旦使用final关键字进行修饰,说明不可改变。

            注意事项:

            1. 接口当中的变量,可以省略public static final,但是不写也是这样
            2. 接口当中的常量,必须进行赋值,不能不赋值
            3. 接口当中常量的名称,使用完全大写的字母,用下划线进行分隔
    8. 接口小结

      在Java9+版本中,接口的内容可以有:

      1. 成员变量其实是常量,格式:

        public static final 数据类型 常量名称 = 数据值;

        注意:

        ​ 常量必须进行赋值,而且一旦赋值不能改变。

        ​ 常量名称完全大写,用下划线进行分隔。

      2. 接口中最重要的就是抽象方法,格式:

        public abstract 返回值类型 方法名称(参数列表);

        注意:实现类必须覆盖重写接口所有的抽象方法,除非实现类是抽象类。

      3. Java8开始,接口允许定义默认方法,格式:

        public default 返回值类型 方法名称(参数列表) { 方法体 }

        注意:默认方法也可以被覆盖重写。

      4. Java8开始,接口里允许定义静态方法,格式:

        public static 返回值类型 方法名称(参数列表) { 方法体 }

        注意:应该通过接口名称进行调用,不能用过实现类对象调用接口静态方法。

      5. Java9开始,接口里允许定义私有方法,格式:

        普通私有方法:private 返回值类型 方法名称(参数列表) { 方法体 }

        静态私有方法:private static 返回值类型 方法名称(参数列表) { 方法体 }

        注意:private的方法只有接口自己才能调用,不能被实现类或别人使用。

      6. 一些注意事项:

        使用接口的时候,需要注意:

        1. 接口是没有静态代码块或者构造方法的。

        2. 一个类的直接父类是唯一的,但是一个类以同时实现多个接口。

          格式:

          public class MyInterfaceImpl implements MyInterfaceA, MyInterfaceB{
          	// 覆盖重写所有抽象方法
          }
          
        3. 如果实现类所实现的多个接口当中,存在重复的抽象方法,那么只需要覆盖重写一次即可。

        4. 如果实现类没有覆盖宠溺小额所有接口当中的所有抽象方法,那么实现类就必须是一个抽象类。

        5. 如果实现类所实现的多个接口当中,存在重复的默认方法,那么实现类一定要对冲突的默认方法进行覆盖重写。

        6. 一个类如果直接继承父类当中的方法,和接口当中的默认方法产生冲突,优先用父类当中的方法。

      7. 接口之间的多继承

        1. 类与类之间是单继承的,直接父类只有一个。

        2. 类与接口之间是多实现的,一个类可以实现多个接口。

        3. 接口与接口之间是多继承的。

          注意事项:

          1. 多个父类接口当中的抽象方法如果重复,没关系
          2. 多个父类接口当中的默认方法如果重复,那么子类接口必须进行默认方法的覆盖重写(而且带着default关键字)。
    9. 多态

      1. 代码当中体现多态性,其实就是一句话,父类引用指向子类对象。

        格式:

        父类名称 对象名 = new 子类名称();

        或者:

        接口名称 对象名 = new 实现类名称();

      2. 访问成员变量的两种方式:

        1. 直接通过对象名称访问成员变量,看等号左边是谁,优先用谁,没有则向上找。
        2. 间接通过成员方法访问成员变量,看该方法属于谁,优先用谁,没有则向上找。
      3. 在多态的代码当中,成员方法的访问规则是:看new的是谁,就优先用谁,没有则向上找。

        成员变量:编译看左边,运行还看左边

        成员方法:编译看左边,运行看右边

        解释:

        // 只要p是student的接口,就可以通过编译(看左边)
        Person p = new Student();
        p.name	// 是person的name值(看左边)
        p.eat()	// student的eat方法优先,没有向上找(看右边),必须是重写父类的方法,自己特有的不行
        
        1. 对象的向上和向下转型

          1. 向上转型:

            格式:父类名称 对象名 = new 子类名称();

          2. 向下转型行:

            格式:子类名称 对象名 = (子类名称)父类对象;

          3. 注意事项:

            1. 必须保证对象本来创建的时候就是猫,才能向从动物下转型成为猫。
            2. 如果对象创建的时候本来不是猫,现在非要向下转型成为猫,就会报错。ClassCastException
      4. instanceof关键字

        public staic void giveMeAPet(Animal animal){
            if(animal instanceof Dog){
                Dog dog = (Dog)animal;
                dog.watchHouse();
            }
            if(animal instanceof Cat){
                Cat cat = (Cat)animal;
                cat.catchMouse();
            }
        }
        
    10. final关键字

      final关键字代表最终、不可改变的。

      常见四种用法:

      1. 可以用来修饰一个类

        public final class 类名称{
        	// ...
        }
        // 当前这个类不能有任何的子类。
        // 一个类如果是final的,那么其中所有的成员方法都无法进行覆盖重写
        
      2. 可以用来修饰一个方法

        权限修饰符 final 返回值类型 方法名称(参数列表){
        	// 方法体
        }
        // 当final关键字用来修饰一个方法的时候,这个方法就是最终方法,也就是不能被覆盖重写。
        // 对于类、方法来说,abstract关键字和final关键字不能同时使用,因为矛盾。
        
      3. 可以用来修饰一个局部变量

        final Student stu = new Student("张三");
        // 一旦使用final用来修饰局部变量,那么这个变量就不能进行更改。
        // 一次赋值,终生不变
        
      4. 可以用来修饰一个成员变量

        对于成员变量,如果使用final关键字修饰,那么这个变量照样是不可变。
            1.由于成员变量具有默认值,所以用了final之后必须手动赋值,不会再给默认值了。
            2.对于final的成员变量,要么使用直接赋值,要么通过构造方法赋值。二者选其一。
            3.必须保证类当中所有重载的构造的方法,都最终会对final的成员变量进行赋值。
        
    11. Java的四种权限修饰符

      在这里插入图片描述

    12. 内部类重名时的访问问题

      public class Outer{
          int num = 10;
          public class Inner{
              int num = 20;
              public void methodInner(){
                  int num = 30;						// 内部类方法的局部变量
                  System.out.println(num);			// 30 局部变量,就近原则
                  System.out.println(this.num);		// 20 内部类的成员变量
                  System.out.println(Outer.this.num);	// 10 外部类的成员变量
              }
          }
      }
      
    13. 内部类的使用

      1. 成员内部类

        1. 成员内部类的定义格式:

          修饰符 class 外部类名称{
              修饰符 class 内部类名称{
                  // ...
              }
              // ...
          }
          // 注意:内用外,随意访问;外用内,需要内部类对象。
          
        2. 使用成员内部类的两种方式:

          1. 间接方式:在外部类的方法当中,使用内部类,然后main只是调用外部类的方法。
          2. 直接方式,公式:
            ​ 类名称 对象名 = new 类名称();
            ​ 外部类名称.内部类名称 对象名 = new 外部类名称().new 内部类名称();
      2. 匿名内部类:

        如果接口的实现类(或者是父类的字类)只需要使用唯一的一次,那么这种情况下就可以省略掉该类的定义,而改为使用匿名内部类。

        匿名内部类的定义格式:

          接口名称 对象名 = new 接口名称(){
          	// 覆盖重写所有抽象方法
          }
          MyInterface obj = new MyInterface(){
              @Override
              public void method(){
                  System.out.println("hello world");
              }
          }
          obj.method();
        

        ​ 对格式"new 接口名称() {…}"进行解析:

        ​ 1. new代表创建对象的动作

        ​ 2. 接口名称就是匿名内部类需要实现那个接口

        ​ 3. {…}这才是匿名内部类的内容

        另外还要注意几点问题:

        1. 匿名内部类,在创建对象的时候,只能使用唯一一次。如果希望多次使用对象,那么就必须使用单独定义的实现类了。

        2. 匿名对象,在调用方法的时候,只能调用唯一一次。如果希望同一个对象,调用多次方法,那么必须给对象起个名字。

        3. 匿名内部类是省略了实现类/子类名称,但是匿名对象是省略了对象名称。

        4. 强调:匿名内部类和匿名对象不是一回事!!!

        5. 匿名内部类如果希望访问所在方法的局部变量,那么这个局部变量必须是有效final的。

          PS:从Java8+开始,只要局部变量事实不变,那么final关键字可以省略,实际上是一个语法糖,底层给加了final。

          原因:为了保护数据的一致性。因为内部类访问局部变量实际上是把这个局部变量传入自己的构造器,作为自己的一个成员变量进行访问。因此,如果局部变量后期改变了,此时内部类不知道,会造成数据不一致的后果

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值