Java面向对象

235 阅读7分钟

语法格式

修饰符 class 类名{
  属性声明;
  方法声明;
}
//修饰符public:类可以被任意访问,类的正文要用{}括起来

属性声明

修饰符 类型 属性名[ = 初值];
//修饰符 public 该属性可以类外的方法访问
//private 该属性只能在类中访问
  • 成员变量
    • 实例变量(不以static修饰)
    • 类变量(static修饰,通过类名.属性名直接使用)
  • 局部变量
    • 形参
    • 方法局部变量
    • 代码块局部变量

可变个数参数

//使用数组方式
//无参数,也要填[]或null
public void printInfo(String[] args){
  for(int i= 0; i< args.length; i++)
  	System.out.println(args[i]);
}
//使用Java特有...方式
//使用方法与数组方式相同,传递参数直接用逗号隔开,不用数组形式
//无参数可不填
//这种方式如果多个形参,...一定要在最后的参数上
public void printInfo(String... args){
  for(int i= 0; i< args.length; i++)
  	System.out.println(args[i]);
}

访问修饰符

修饰符类内部同一个包子类任何地方
privateYES
缺省YESYES
protectedYESYESYES
publicYESYESYESYES

构造方法

public class Test{
  public Test(){//构造函数前的修饰符与类名前的修饰符相同
    //不写构造函数,默认会有,写了则会使用自己写的构造函数
  }
  public Test(String a){
    //不同的参数的同名构造函数可以形成重载
  }
}

关键字——super

  • super可用于访问父类中定义的属性
  • super可用于调用父类中定义的成员方法
  • super可用于在子类构造方法中调用父类的构造方法
  • 注意
    • 尤其当子父类出现同名成员时,可以用super进行区分
    • super的追溯不仅限于父类
    • superthis的用法很像,this代表本类对象的引用,super代表父类的内存空间的标识
    • 在父类只有有参构造函数可以使用的时候,子类必须显式的构建一个构造函数来调用父类的有参构造,并且调用父类构造函数方法要写在第一行

this和super的区别

区别点thissuper
访问属性访问本类中的属性,如果本类没有此属性则从父类中继续查找访问父类的属性
调用方法访问本类中的方法直接访问父类的方法
调用构造函数调用本类的构造函数,必须放在构造函数的首行调用父类构造函数,必须在子类构造函数首行
特殊表示当前对象无此概念

关键字——static

  • 使用范围
    • 在Java类中,可用static修饰属性、方法、代码块、内部类
  • 被修饰后的成员具备以下特点
    • 随着类的加载而加载
    • 优先于对象存在
    • 修饰的成员,被所有对象共享
    • 访问权限允许时,可不创建对象,直接被类调用

初始化块

//注释为执行顺序
public class Test{
  //1 初始化变量默认值
  String name;
  //3
  public Test(){
    this.name = "123";
    System.out.pirntln("构造函数代码被执行");
  }
  //2
  {
    System.out.pirntln("初始化块代码被执行");
  }
  //0
  static{
    //只能使用静态static修饰的属性或方法,实际开发中用来初始化静态属性
    //不管被实例化几次,都只执行一次
  }
}

非静态代码块

​ 没有static修饰的代码块

  1. 可以有输出语句。
  2. 可以对类的属性声明进行初始化操作。
  3. 可以调用静态和非静态的变量或方法。
  4. 若有多个非静态的代码块,那么按照从上到下的顺序依次执行。
  5. 每次创建对象的时候,都会执行一次。且先于构造器执行

静态代码块

​ 用static修饰的代码块

  1. 可以有输出语句。
  2. 可以对类的属性声明进行初始化操作。
  3. 不可以对非静态的属性初始化。即:不可以调用非静态的属性和方法。
  4. 若有多个静态的代码块,那么按照从上到下的顺序依次执行。
  5. 静态代码块的执行要先于非静态代码块。
  6. 静态代码块只执行一次

用处

public class Test{
  public static void main(String[] args){
    Person p = new Person(){
      //匿名内部类  匿名子类
      //Person类中的name属性已经初始化为张三,如何修改为李四
      {
        super.name = "李四";
      }
    }
  }
}

静态导入包

//可以直接使用random()来调用
import static java.lang.Math.random;

关键字——final

  • final标记的类不能被继承。提高安全性,提高程序可读性。

    String类、System类、StringBuffer

  • final标记的方法不能被子类重写。

    Object类中的getClass()方法

  • final标记的变量(成员变量或局部变量)即称为常量。名称大写,且只被赋值一次

    final double PI = 3.14;

    final static double Pi =3.14;final static修饰即为全局常量

抽象类

  • abstract关键字来修饰一个类时,这个类叫做抽象类
  • abstract来修饰一个方法时,该方法叫做抽象方法。 抽象方法:只有方法的声明,没有方法的实现。以分号结束:abstract int abstractMethod(int a);
  • 含有抽象方法的类必须被声明为抽象类。
  • 抽象类不能被实例化。抽象类是用来被继承的,抽象类的子类必须重写父类的抽象方法,并提供方法体。若没有重写全部的抽象方法,仍为抽象类。
  • 不能用abstract修饰属性、私有方法、构造器、静态方法、final的方法。

内部类

在Java中,允许一个类的定义位于另一个类的内部,前者称为内部类,后者称为外部类。

  • 内部类一般用在定义它的类或语句块之内,在外部引用它时必须给出完整的名称。
  • 内部类的名字不能与包含它的类名相同;
  • 内部类可以使用外部类的私有数据,因为它是外部类的成员,同一个类的成员之间可相互访问。而外部类要访问内部类中的成员需要:内部类.成员或者内部类对象.成员
  • 分类:
    • 成员内部类(static成员内部类和非static成员内部类)
    • 局部内部类(不谈修饰符)、匿名内部类
public class Test{
  int i;
  public int z;
  private int k;
  
  class A{
    int i;
    public void setTest(){
      Test.this.i=1;
      Test.this.z=2;
      Test.this.k=3;
    }
    public void setMyself(){
      this.i=4;
    }
  }
  
  public void setInfo(){
    new A().setTest();
  }
  public void showInfo(){
    System.out.println(this.i);
    System.out.println(this.z);
    System.out.println(this.k);
  }
  public static void main(String[] args){
    Test t = new Test();
    t.setInfo();
    t.showInfo();
  }
}

特性

  • 可以声明为final
  • 和外部类不同,Inner class可声明为privateprotected
  • Inner class 可以声明为static的,但此时就不能再使用外层类的非static的成员变量
  • Inner class作为类:
    • 可以声明为abstract类,因此可以被其它的内部类继承
  • 【注意】非static的内部类中的成员不能声明为static的,只有在外部类或static的内部类中才可声明static成员。

作用

​ 解决Java不能多重继承的问题。

public class Test{
  public static void main(String[] args){
    A a = new A();
    a.method2();
    a.method3();
  }
}
//A中想要使用BC中的方法,但是Java不支持多重继承
//所以用内部类继承,再重写
class A{
  public void method2(){
    new InnerB().method2();
  }
  
  public void method3(){
    new InnerC().method3();
  }
  private class InnerB extends B{
    @Override
    public void method2(){
      System.out.println("这是重写后的method2");
    }
  }
  
  private class InnerC extends C{
    @Override
    public void method3(){
      System.out.println("这是重写后的method3");
    }
  }
}

class B{
  public void method2(){
    
  }
}

class C{
  public void method3(){
    
  }
}

JVM

内存模型

实例化原理

关键字——package

  • package语句作为java源文件的第一条语句,指明该文件中定义的类所在的包。
  • 若缺省该语句,则指定为无名包
  • 格式为package 顶层包名.子包名
  • 通常包名小写单词,类名首字母大写
  • 一般利用公司域名倒置作为包名比如,com.baidu.www

关键字——import

  • 引用别的包
  • 同一个包下面,不用引用
  • import 包名.类名
  • 可以用*表示所有

instanceof

对象 instanceof 类名;
//返回值为布尔值
//判断是否为该类所实例化的对象

JavaBean

  • JavaBean是一种Java语言写成的可重用组件
  • JavaBean是指符合以下标准的类
    • 类是公共的
    • 有一个无参的公共的构造函数
    • 有属性,且有对应的getset方法

继承

修饰符 sonClass extends superClass{
  
}
  • 继承的出现提高了代码的复用性
  • 继承的出现让类与类之间产生了关系,提供了多态的前提
  • 不要仅为了获取其他类中的某个功能而去继承
  • Java只能单继承,一个子类只有一个父类

组合

​ 在面向对象编程原则中,组合>继承。

//这是继承
class A extends B{
    ...
}
//这是组合,可以使用B的全部功能,优先使用这种方法
class A{
    Public B b;
}

方法重写

@Override
public void showInfo(){
  
}
  • 重写方法必须和被重写方法具有相同的方法名称、参数列表和返回值类型
  • 重写方法不能用比被重写方法更严格的修饰符
  • 重写和被重写的方法必须同时为static或者为非static
  • 子类方法抛出的异常不能大于父类被重写方法的异常

多态

  • 两种体现
    • 方法的重载(overload)和重写(overwrite)
    • 对象的多态性,可以直接应用在抽象类和接口上
  • Java引用变量有两种类型,编译时类型和运行时类型。前者由声明变量时使用的类型决定,后者由实际赋值的类型决定
    • 若编译时类型和运行时类型不一致,就会出现多态(Polymorphism)

向上转型

//Student类是Person类的子类
Person p = new Person();
Person e = new Student();
//不能调用Student中新增的属性或方法

小结

  • 前提
    • 需要存在继承或者实现关系
    • 需要覆盖操作
  • 成员方法
    • 编译时,要查看引用变量所属的类是否存在所调用的方法
    • 运行时,调用实际对象所属的类中的重写方法
  • 成员变量
    • 不具备多态性,只看引用变量所属的类

Object类

  • Object类是所有Java类的跟父类,基类
  • 如果在类的声明中没有extends,那么默认指定继承于Object
  • 在方法中,参数需要一个对象,但是不知道是什么类,可以用Object类作为形参

对象类型转换

  • 对Java对象的强制类型转换称为造型

    • 从子类到父类的类型转换可以自动进行

      Son son = new Son();
      Father faher = son;
      
    • 从父类到子类的类型转换需要造型(强制类型转换)实现

      Father father = new Father();
      Son son = (Son)father;
      
    • 无继承关系的引用类型间的转换是非法的

==和equal

  • ==
    • 在两个基本类型之间比较,只要两个变量相等,即为true
    • 在两个引用类型之间比较,需要两个引用指向同一个对象时,才返回true
    • ==进行比较时,符号两边的数据类型必须兼容(可自动转换的基本类型除外),否则编译出错
  • equal()
    • 所有的类都继承于Object类,所以所有的类都有equal()方法
    • 该方法和==相同,但只能比较两个引用类型
    • 特例:对FileStringDate及包装类(wrapperClass)来说,是比较类型和内容而不考虑引用的是否是同一个对象,原因是在类中重写了equal()方法
    • PS:比较字符串用equal方法而不是==

包装类

基本数据类型包装类
booleanBoolean
byteByte
shortShort
intInteger
longLong
charCharacter
floatFloat
doubleDouble

装箱

  • 通过包装类的构造函数实现

    int i = 500;
    Integer t = new Integer(i);
    Integer t1 = 500;//自动装箱
    
  • 还可以通过字符串参数构造包装类对象

    Float f = new Float("4.56");//字符串内容一定要符合类型,不然NumberFormatException
    

拆箱

  • 调用包装类的xxxValue()方法

    boolean b = bObj.booleanValue();
    boolean b = bObj;//自动拆箱
    
  • JDK1.5后,支持自动装箱,自动拆箱,但类型必须匹配

字符串转换基本数据类型

  • 通过包装类的构造器实现

    int i = new Integer("111");
    
  • 通过包装类的静态方法实现

    Float f = Float.parseFloat("12.1");
    

基本类型转换成字符串

  • 调用字符串重载的valueOf()方法

    String fstr = String.valueOf(2.34f);
    
  • 更直接

    String intStr = 5 + "";
    

设计模式

​ 设计模式是在大量的实践中总结和理论化之后优选的代码结构、编程风格、以及解决问题的思考方式。设计模式就像是经典的棋谱,不同的棋局,我们用不同的棋谱,免去我们自己再思考和摸索。

单例设计模式

​ 所谓类的单例设计模式,就是采取一定的方法保证在整个的软件系统中,对某个类只能存在一个对象实例,并且该类只提供一个取得其对象实例的方法。

​ 如果我们要让类在一个虚拟机中只能产生一个对象,我们首先必须将类的构造方法的访问权限设置为private,这样,就不能用new操作符在类的外部产生类的对象了,但在类内部仍可以产生该类的对象。因为在类的外部开始还无法得到类的对象,只能调用该类的某个静态方法以返回类内部创建的对象,静态方法只能访问类中的静态成员变量,所以,指向类内部产生的该类对象的变量也必须定义成静态的。

​ 使用单例模式解决什么问题?一般都是new对象太费劲,或者频频的new新的对象没有必要。

//饿汉式单例模式
public class Single{
  //私有的构造,构造方法私有化,调用这个类的人就不能直接使用new来创建对象
  private Single(){
    
  }
  //私有的single类型的类变量
  private static Single single =new Single();
  
  public static Single getInstance(){
    reutrn single;
  }
}
//懒汉式
public class Single1{
  private Single1(){
    
  }
  public static Singgle1 single1 = null;
  public static getInstance(){
    if(single1 == null)
      single1 = new Single1();
    return single1;
  }
}

模板设计模式

​ 抽象类

工厂方法

接口

​ 有时必须从几个类中派生出一个子类,继承它们所有的属性和方法。但是,Java不支持多重继承。有了接口,就可以得到多重继承的效果。接口(interface)是抽象方法和常量值的定义的集合。 ​ 从本质上讲,接口是一种特殊的抽象类,这种抽象类中只包含常量和方法的定义,而没有变量和方法的实现。 实现接口类:

class SubClass implements InterfaceA,InterfaceB{}

​ 一个类可以实现多个接口,接口也可以继承其它接口。

接口的特点

  • interface来定义。
  • 接口中的屏有成员变量都默认是由public static final修饰的。
  • 接口中的所有方法都默认是由public abstract修饰的。
  • 接口没有构造器。
  • 接口采用多层继承机制。
public interface Runner{
  int ID = 1;//默认添加了 public abstract final 修饰
  void start();//默认添加了 public abstract 修饰
  public void run();
  void stop();
}

​ 实现接口的类中必须提供接口中所有方法的具体实现内容,方可实例化。否则,仍为抽象类。

​ 接口的主要用途就是被实现类实现。(面向接口编程)

​ 与继承关系类似,接口与实现类之间存在多态性定义刘ava类的语法格式:先写extends,后写implements

接口和抽象类

  • 抽象类需要稳定的抽象,切忌随意更改
  • 新增的常量和方法,通过接口来实现,而不是改造抽象类
  • 抽象类实现接口,不用实现接口中的所有方法