java 面向对象基础

2019-04-15  本文已影响0人  squall1744

内存图


成员变量和局部变量的区别


  1. 在类中的位置不同
    • 成员变量在类中, 在方法外
    • 局部变量在方法内或方法声明中(形参)

public class Phone {
  String x; //成员变量

  public void showPhone() {
    int y; //局部变量
  }
  
}
  1. 内存中位置不同
    • 成员变量在堆内存
    • 局部变量在栈内存
  2. 生命周期不同
    • 成员变量随着对象的消失而消失
    • 局部变量随着方法的消失而消失
  3. 初始化值不同
    • 成员变量有默认值
    • 局部变量没有默认值, 必须先赋值后使用

常用API


nextLine

获取键盘输入的字符串

用法
nextLine属于Scanner类, 所以在使用nextLine时需要先创建Scanner实例, 然后调用Scanner实例的nextLine方法

 Scanner sc = new Scanner(System.in);
 String s = sc.nextLine();

String构造方法

直接赋值String和new String()的区别

String成员方法

判断

获取

StringBuilder类


先看下面的图



当我们对字符串拼接时, 会把拼接的字符串放在方法区常量池的一个新的地址中, 并且我们的变量指向这个新的地址, 这就意味着拼接前的字符串在拼接之后就变成了内存中的垃圾

StringBuilder是一个可变的字符串, 可以在其后随意拼接字符串, 这样我们在拼接字符串时, 就会动态的添加到原字符串后面, 这样就不会造成内存垃圾了

StringBuilder构造方法

StringBulider成员方法

将数组转换成字符串

    public static void main(String[] args) {
          int[] arr = {1,2,3};
          StringBuilder sb = new StringBuilder();
          for(int i = 0; i < arr.length; i++) {
              sb.append(arr[i]);
          }
          String newString = sb.toString();
          System.out.println(newString);
    }

ArrayList


ArrayList数组列表可以动态的创建数组, 并且封装了很多好用的数组成员方法, 可以让我们很方便的操作数组

构造函数

ArrayList<String> arr = new ArrayList<String>(); //创建以字符串为元素的ArrayList实例

成员方法

static和代码块


static关键字

static修饰的静态方法/属性属于类, 所有该类的实例都可以调用, 其随着类而加载, 优先于对象加载

下面的代码, 我们在Student类中定义了一个static属性school, 我们在Student的实例对象p1中并没有给school赋值, 但是我们却可以直接调用p1.school

public class MyPhone {
    public static void main(String[] args) {
        Student p1 = new Student();
        p1.name = "小张";
        p1.age = 20;
        System.out.println(p1.name + ' ' + p1.age + ' ' + p1.school);
    }
}


class Student {
    public static String school = "清华";
    public String name;
    public int age;
}
  1. 由于静态方法和静态属性都是随着类的加载而加载的, 所以静态方法中可以调用静态属性和静态方法
  2. 静态方法中不能调用普通成员变量和成员方法
  3. 静态方法中没有this, 因为静态方法是随类加载的, 所以此时还没有对象

static的应用举例

Math类就是static的典型应用, Math类中的所有方法都是静态方法, 所以我们直接用Math类调用方法就可以了, 不需要创建Math实例, 并且也无法创建Math实例

继承与抽象类


继承就是让其他类拥有某个类中的成员变量和方法, 这个被继承的类就叫做父类

我们用extends关键字来继承类

看下面的代码, 我们让Man继承了Person, 所以我们在创建Man的实例对象时, 我们不但有Man的成员变量agent, 同时还拥有了继承自Person类的name, age属性, 以及say方法, 这样就可以大大减少代码量

class Person {
    String name;
    int age;

    public void say() {
         System.out.println("hello");
     }
}

class Man extends Person {
    String agent;
}

java是单继承语言

java继承中成员变量的特点

java继承中成员方法的特点

class Person {
    String name;
    int age;

    public void say() {
         System.out.println("hello");
     }
}

@Override
class Man extends Person {
    public void say() {
        super.say();
        System.out.println("world");
    }
}

java继承构造方法的执行顺序

class Person {
    String name;
    int age;
    
    public Person() {
        
    }

    public void say() {
         System.out.println("hello");
     }
}

class Man extends Person {
    public Man() {
        super();
    }
    public void say() {
        super.say();
        System.out.println("world");
    }
}

其实这种调用顺序是有原因的, 因为子类继承父类, 所以子类很可能要调用父类中的成员变量或者成员方法, 所以在子类调用之前预先调用父类就是为了如果子类需要用的父类的某些成员变量或者方法前, 先将其初始化

抽象类和抽象方法


abstract修饰的类和成员方法就是抽象类和抽象方法

abstract class Teacher { // 抽象类
    public abstract void say(); // 抽象方法
}

抽象类举例

下面我们抽象一个老师的类

public class MyTeacher {
    public static void main(String[] args) {
        BasicTeacher bt = new BasicTeacher();
        bt.name = "Adam";
        bt.age = 20;
        bt.gender = "male";
        bt.teach();
    }
}

abstract class Teacher {
    String name; // 姓名
    int age; // 年龄
    String gender; // 性别

    public abstract void teach();
}

class BasicTeacher extends Teacher {
    @Override
    public void teach() {
        System.out.println("基础班课程");
    }
}

接口


接口的出现主要是为了结局单一继承的局限性
接口比抽象类更抽象, 它只能有抽象方法
接口可以通过类来实现

nterface Animal {
    public abstract void eat();

}

class Cat implements Animal {
    public void eat() {
       System.out.println("吃鱼");
    }
}

接口的特点

多态


多态的前提条件

看上面的条件可能看不懂, 实际上总的来说就是, 一个子类重写了父类的方法, 然后我们定义了一个父类类型的变量, 然后把这个变量用子类的实例赋值, 看下面的例子

public class MyAnimal {
    public static void main(String[] args) {
        Animal a = new Cat(); // 多态
        a.eat();
    }
}

class Animal {
    public void eat() {

    }

}

class Cat extends Animal {
    public void eat() {
       System.out.println("吃鱼");
    }
}
  1. 我们的Cat类继承了Animal, 并且在Cat类中重写了Animal的eat成员方法
  2. 我们在main方法中声明了一个Animal类型的变量a, 并且将它指向一个Cat实例
  3. 我们调用a的eat方法, 此时调用的是Cat的eat方法

这就是典型的多态例子

多态的成员变量及方法



多态的优缺点
缺点

优点

内部类


分类

成员内部类

所在位置和成员变量和成员方法一样, 同样可以使用修饰符修饰。下面的例子我们在Outer类中间创建了一个内部类:

class Outer {
  private int num = 10;
  
  public void show() {
    Inner in = new Inner(); //创建内部类实例对象
    in.methods(); //调用实例的methods方法, 此时num调用的是Outer的num
    System.out. println("Hello");
  }
  
  // 内部类
  public class Inner {    
    public void methods() {
      System.out.println(num);
    }
  }
}
Outer.Inner in = new Outer().new Inner();

局部内部类

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

class Outer {
    private int num = 10;
    public void show() {
         // 局部内部类
        class Inner {
            private int num2 = 10;

            public void methods() {
            }
        }
        Inner in = new Inner();
        in.methods();
    }
}

匿名内部类

定义在方法内部的没有类名的内部类, 匿名内部类实际上是对某个类的继承或对某些接口的实现, 所以在使用匿名内部类时, 必须预先定义其父类或接口

class Outer {
  private int num = 10;
  
  public void show() {
     // 匿名内部类
    new Inner() {
      public void function() {}
    };
  }
}

//匿名内部类实现的接口
interface Inner {
  public void function();
}

我们还可以利用多态把匿名内部类赋值给类型为匿名内部类的父类的变量来实现匿名内部类, 如:

Inner i = new Inner(){
    public void function() {}
};

泛型


泛型是Java中一个非常重要的知识点,在Java集合类框架中泛型被广泛应用。

泛型类

假设我们创建以下Box类:

class Box{
  private String object;
  public void set(String str) {
    this.object = str;
  }
  public String get(){
    return object;
  }
}

Box有一个非常明显的局限, 只能传String类型的成员变量, 当我们要传int类型的成员变量时, 就必须要重写Box, 这要那个Box的复用性就很差了

class Box<T>{
  private T object;
  public void set(T t) {
    this.object = t;
  }
  public T get(){
    return object;
  }
}

这样我们的Box类便可以得到复用,我们可以将T替换成任何我们想要的类型:

Box<Integer> integerBox = new Box<Integer>();
Box<Double> doubleBox = new Box<Double>();
Box<String> stringBox = new Box<String>();

泛型方法

明一个泛型方法很简单,只要在返回类型前面加上一个类似<K, V>的形式就行了:

public class Util {
    public static <K, V> boolean compare(Pair<K, V> p1, Pair<K, V> p2) {
        return p1.getKey().equals(p2.getKey()) &&
               p1.getValue().equals(p2.getValue());
    }
}
public class Pair<K, V> {
    private K key;
    private V value;
    public Pair(K key, V value) {
        this.key = key;
        this.value = value;
    }
    public void setKey(K key) { this.key = key; }
    public void setValue(V value) { this.value = value; }
    public K getKey()   { return key; }
    public V getValue() { return value; }
}

我们可以像这样调用泛型方法

Pair<Integer, String> p1 = new Pair<>(1, "apple");
Pair<Integer, String> p2 = new Pair<>(2, "pear");
boolean same = Util.<Integer, String>compare(p1, p2);

多线程


上一篇下一篇

猜你喜欢

热点阅读