java面向对象静态和多态性

static和多态性

  • sctatic
    • 定义常量
    • 静态方法
    • 静态块
    • 非静态块
    • 方法中的可变长个数的参数
    • 静态导入
  • 基本数据类型的对象缓存
    • 字符串缓存池
  • 面向对象设计思想的要点
      • 依赖关系
      • 关联关系
      • 继承关系
  • 多态性
      • 三个定义和两个方法。
        • 多态分为两种:
    • 对象的多态性
      • 多态在代码中的体现
    • 类间多态和类内多态
      • 类间多态性
      • 类内多态性
    • 方法的重写和重载
      • 方法的重写(覆盖)
      • 方法的重载
    • 多态的优点

sctatic

访问的方式

  • 可以使用“类名.静态属性名”或者“对象名.静态属性名”的方式进行访问。【范围限制】

定义常量

命名规则:名称全大写,下划线分词

  • 声明语法:public static final double MIN_NUMBER = 0.1;
  • 声明的同时直接进行初始化
    public static final double MIN_NUMBER = 0.1;
  • 先声明后在static静态块中赋值
public static final double MIN_NUMBER;
static{
     
MIN_NUMBER=0.1;
}

静态方法

  • 因为可以直接使用”类名.方法名”的形式直接调用静态方法,静态方法执行时很有可能并没有构建对象,所以在静态方法中不允许使用this/super之类用于指定对象的关键字
public class B{
     
private Random random;
public static void pp(){
     
System.out.println("pp...");
//静态方法的调用没有要求必须构建B对象,所以很有可能random根本不存在,要求在静态方法中不能访问非静态成员
}
public static void main(String [] args){
     
B.pp();//调用当前类中的static方法,可以直接方法名.pp()
}
}
  • 当然在静态方法中允许创建对象,并调用对象方法
  • 静态方法只能直接访问静态成员,不能直接访问非静态成员

静态块

public class A{
     
static {
      //类内,所有方法之外
System.out.println("静态代码块");
}
}
  • 类在执行时需要通过一个叫作类加载器的组件将程序加载到内存中,类在运行时一般不会发生变化,所以类不会频繁加载,在整个运行过程中只加载一次,而且常驻内存
  • 静态块在类加载完毕后自动执行,而且只执行一次
 public class B{
     
 static {
     
System.out.println("static...");
 }
 public static void main(String[] args) {
     
}
}

非静态块

  • 非静态块在类内且在所有的方法之外,非静态块并不会在类加载后自动执行,而是在构建当前对象时自动执行。
  • new一次则会执行一次,执行时机在构造器之前执行

需要注意的是

  • 当类加载完毕会自动优先处理static属性和static块,这两个优先级是相同的,所以谁在前先处理谁
  • new对象时,处理非静态属性和非静态块,这两个优先级是相同的,所以谁在前先处理谁
  • 最后执行构造器
  • 静态方法只能访问静态成员,静态有访问局限性
  • 静态方法中不能有this super关键字
  • 主函数是静态的

什么时候使用静态

  • 当成员变量的数据在当前类的各个对象都相同时,可以用static修饰的,让多个对象共享
  • 非静态方法的调用没特殊要求,构建对象后即可调用;静态方法可以通过类名称直接调用,无需创建对象
  • 非静态方法可以使用静态或者非静态成员;静态方法只能访问静态成员
  • 如果类中的功能都是静态的,那么该类创建对象是没有意义的,所以构造方法需要私有化

方法中的可变长个数的参数

  • 语法:数据类型… 变量名。-必须作为最后一个参数出现
  • 具体处理过程中实际上是按照数组的方式进行处理,而且数组不会为null

静态导入

在一个类中反复使用到某个类中的静态方法,如果使用静态导入则在当前类中不需要再写类名称

double a1=-12.345;
 System.out.println(Math.abs(a1));
 System.out.println(Math.cos(a1));
 System.out.println(Math.sin(a1));

在JDK5当中提供了导入静态方法的import语句。

  • 语法:import static java.lang.Math.*; - 导入Math类中的所有静态方法
  • 如果有多个静态导入操作,则所声明的静态方法不能重复,否则报错
  • 注意要求使用JDK1.5+版本,否则编译不通过
 import static java.lang.Math.*;
public class Test1 {
     
public static void main(String[] args) {
     
 double a1 = -12.345;
 System.out.println(abs(a1));
 System.out.println(cos(a1));
System.out.println(sin(a1));
}
}

基本数据类型的对象缓存

在Integer类定义中查看源代码可以发现一个定义

private static class IntegerCache {
     }这实际上就是Integer的cache
Integer num1 = 12;//自动装箱
 Integer num2 = 12;//块相等,<=127都是真的
 System.out.println(num1 == num2);

是因为在Integer中包含有一个缓存池,缓存值为-128到127之间。

  • Integer\Long\Short\Byte中都有缓存池
  • 定义Integer k1=12是先在缓存池中查找12这个对象,如果有则直接使用
  • new Integer(12)一定会引发对象的创建,而不管缓存池中是否包含这个对象

字符串缓存池

String中包含一个缓存池,当使用某个字符串对象时会首先在缓存池中进行查找,如果存在则直接返回这个对象的地址;如果不存在则会在缓存池中进行创建,创建完成后返回地址

String s1="abc";
 String s2="abc";
 String s3=new String("abc");//这里会创建2个对象,一个在缓存池中,一个是new导致的新创建对象
 System.out.println(s1==s2);//true
 System.out.println(s1==s3);//false
 
 String s1="abc";
 String s3="ab";
 String s2=s3+"c";
 System.out.println(s1==s2);//false

如果通过字串拼接所得内容和某个字串内容一致,但是引用不同

面向对象设计思想的要点

认为客观世界由各种对象组成,任何事物都是对象,复杂的对象可以由比较简单的对象以某种方式组合而成

  • 把所有对象都划分成各种对象类,每个对象类都定义了一组数据和一组方法
  • 按照子类与父类的关系,把若干个对象类组成一个层次结构的系统
  • 对象彼此之间仅能通过传递消息互相联系

依赖关系

一个类中,使用到了另外一个类
B类方法中使用了A类,此时B类依赖于A类

public class B{
     
public void pp(){
     
A a=new A();
a.abc();
}
}

关联关系

某个类的属性是另外一个类
B类中的属性是A类的引用,此时B类和A类发生了关联关系

public class B{
     
private A a;
}

继承关系

某个类继承了另外一个类
B类继承了A类,此时B类和A类的关系是继承关系

多态性

  • 多态性是发送消息给某个对象,让该对象自行决定响应何种行为。通过将子类对象引用赋值给超类对象引用变量来实现动态方法调用

三个定义和两个方法。

  • 三个定义分别是父类定义子类构建、接口定义实现类构建和抽象类定义实
    体类构建,而两个方法分别是方法重载和方法重写。

多态分为两种:

  • 编译时多态:方法的重载
  • 运行时多态:JAVA运行时系统根据调用该方法的实例的类型来决定选择调用哪个方法则被称为运行时多态

对象的多态性

继承表示的是is a的语义

public class 汽车 extends 车库{
     }//错误的
 public class 学生 extends{
     }//正确的,因为任何一个学生都是人
  • 编程是对现实世界的模拟体现

多态在代码中的体现

父类或者接口的引用指向其子类的对象。例如:动物 x=new 猫()

public class Test1 {
     
 public static void main(String[] args) {
     
动物 x1 = new 动物();
 猫 x3=new();//语法正确
 // 猫 x4=new 动物(); 语法错误
动物 x2 = new();// 猫extends动物,表示猫具有动物的所有特性,同时猫具备一些自己都有的特性
  • 静态方法中不能直接访问非静态成员,但是普通方法允许直接调用其他成员方法,当然也允许直接调用静态方法
  • 对象多态性可以使程序有良好的扩展,并可以对所有类的对象进行通用处理

多态引用时,构造子类对象时的构造方法的调用顺序

  • 父类 bi=new 子类(); bi可以直接调用父类中声明的方法,但是具体执行的方法取决于new
    的是谁。如果需要调用子类中的特殊方法,则必须先进行强壮类型转换
  • 先调用超类的构造方法,多重超类首先调用最远超类的方法
  • 然后再执行当前子类的构造方法

类间多态和类内多态

  • 多态是同一个行为具有多个不同表现形式或形态的能力。多态就是同一个接口,使用不同的实例而执行不同操作

类间多态性

父子类之间的一种多态型,例如:动物 x = new 猫()

public class Test1 {
     
public static void main(String[] args) {
     
 Animal a1=new Cat();
 A a=new A();
 a.eee(a1);
}
}
 class A{
     
public void eee(Animal animal){
     
animal.eat();
}
 }
 class Animal{
     
public void eat(){
     
System.out.println("Animal.eat()");
}
 }
 class Cat extends Animal{
     
 @Override
 public void eat() {
     
System.out.println("就是爱老鼠");
}
 }
 class Dog extends Animal{
     
 @Override
 public void eat() {
     
System.out.println("就是爱肉骨头");
}
}
  • 方法调用中的限制:
    针对一个类对象有两种类型,一种称之为编译期类型,编译时系统识别对象的类型,”动物 x = new 猫()”在编译时,系统识别x是动物类别的,所以只能调用动物类定义的方法,而不能调用猫中特殊的方法。另外一种称
  • 覆盖的方法一定不能是private的

类内多态性

在一个类对象上调用相同名称的方法,但是当参数不同时执行不同的动作

  • java中定义方法允许使用…表示不确定个数的参数
    不确定个数的参数必须是方法声明时最后一个参数,一个方法中只允许一个不确定个数的参数

方法的重写和重载

方法的重写(覆盖)

  • 要求:方法的名称一致
    方法的重写(覆盖)一定发生在父子类之间
public class Test4 {
     
public static void main(String[] args) {
     
 F4 f=new F4(); f.pp(10);
 S4 s=new S4(); s.pp(10);
F4 fs=new S4(); fs.pp(10);
}
}
class F4 {
     
public void pp(int k) {
     
System.out.println("F4.pp(int)");
}
}
class S4 extends F4 {
     
public void pp(int k) {
      //子类中定义的同名同参数的方法覆盖了父类中的方法定义,如果需要调用父
类中的方法则需要使用super.pp(k)进行调用
System.out.println("S4.pp(int)");
}
}
  • 执行规则:new谁运行谁的方法,和声明的类型无关,由具体创建对象的类型决定
    方法的覆盖定义要求方法名称一致
public class Test1 {
     
public static void main(String[] args) {
     
Fa f2 = new Son();
f2.pp(12);// Son中的pp方法定义覆盖了Fa中的pp方法,new的是Son,所以执行的是Son中的方法
}
}
class Fa {
     
public void pp(Number kk) {
     
System.out.println("Fa...");
}
class Son extends Fa {
     
public void pp(Integer kk) {
     
System.out.println("Son...");
}
}
  • 子类中方法范围要求大于等于父类中的方法范围,不允许private 返回类型一致,子类方法可以小于等于父类

  • 类型,例如父类Number,子类Integer 参数类型一致

  • 方法的参数一致(个数、类型、顺序),和参数名称无关

  • 返回数据类型一致(因为如果返回类型不一致,则无法进行语法检查,例如父类返回Double,而子类返
    回Integer,调用处语法检查是按照Double进行检查还是按Integer检查?允许父类中返回的是父类型,而子类中返回子类型,例如父类中返回的是Number类型,而子类中返回的是Integer)

  • 抛出异常一致,注意实际上允许子类抛出比父类更少的异常

  • 要求子类中的方法范围 >= 父类中方法范围

  • 静态方法覆盖和调用::用谁声明则调用谁的静态方法

@Override//注解可以使IDE工具在编译源代码时进行检查,如果有手写错误则IDE工具报错`

方法的重载

方法的名称相同,参数不同,和返回值类型无关。可以在一个类内或者父子类之间
调用规则:类型最佳匹配原则

class A5 {
     
public void pp(){
     
System.out.println("A5.pp()");
}
public int pp(){
     }//语法错误,因为在系统中识别一个方法是用【方法名称+参数类型列表】进行,系统会将这两个pp方法识别为同一个方法。注意:在一个类中不允许方法相同
public void pp(int k){
     
System.out.println("A5.pp(int)");
}
}
class B5 extends A5 {
     
public void pp(String k){
     
System.out.println("B5.pp(String)");
 }
 public void pp(String k,int k1){
     }
public void pp(int k,String k1){
     }
}
  • 要求:方法名称相同并且参数不同。参数不同有3种情况:参数个数不同、参数类型不同、参数顺序不同
    ----和参数名称无关
  • 和返回类型无关
- public double pp(int k){
     }
 public int pp(int k){
     }
 // 一个方法有返回值,调用处实际上可以不接收。假设系统可以按照返回类型将这两个方法识别为不同方法,则调用pp(10)就没办法判断到底执行哪个
  • 和范围无关
public void pp(){
     }
 protected void pp(){
     }//语法报错
  • 和方法抛出的异常无关
  • 方法的重载可以出现父子类之间,也可以是在一个类内。但是方法的覆盖一定是父子类之间,不能在一个类内实现方法的覆盖

多态的优点

  • 消除类型之间的耦合关系
  • 可替换性、可扩充性
  • 接口性、灵活性、简化性
public class Test1 {
     
public static void main(String[] args) {
     
 Fa ff = new Son();
 ff.pp(10);因为在父类中声明的方法为Integer类型,所以在执行前会自动执行装箱操作,所以调用
的是从父类中继承到的pp(Integer),而不是最佳匹配的pp(int)
}
}
class Fa {
     
protected void pp() {
     
System.out.println("Fa.pp()");
 }
 public void pp(Integer kk){
     
System.out.println("Fa.pp(Integer)");
}
}
class Son extends Fa {
     
public int pp(int k) {
     
 System.out.println("Son.pp(int)");
 return 10;
}
}

你可能感兴趣的:(java,java,编程语言,多态,类)