栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Java基础

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Java基础

目录

面向对象

方法(类似C语言中的函数)

可变参数

         全局变量与局部变量

构造方法/构造器

方法/构造方法重载

this关键字

封装

继承

super 关键字

方法重写/覆盖

多态

多态的向上转型


Java常识及编写规范

运行机制

.java文件         编译javac     生成.clsss文件      通过JVM运行Java

源文件             编译             字节码文件           运行Java

相对路径:从当前文件夹(目录)开始定位,形成的路径

绝对路径:从根文件夹(目录)开始定位,形成的路径

JDK = JRE + 开发工具包

JRE = JVM + 核心类库

//Java编写步骤

1.编写java的源代码

2.java.c编译,得到对应的.class字节码文件

3.java运行,本质就是把.class文件加载到JVM运行

1.类,方法的注释,使用javadoc的方式,即文档注释

2.非Javadoc注释,往往是对代码的说明(程序的维护者)说明如何修改,注意事项

3.使用tab,整体将代码右移,使用shift+tab整体左移

4.运算符和 = 的两边,给空格,使代码看上去清楚

5.源文件编码使用utf-8编码

6.行宽字符不要超过80

7.编码风格:次行风格 行尾风格

// public class Hello是一个类,是一个public(公有)的类
// Hello{}表示一个类的开始和结束
// public static void main(String[] args)表示一个主方法,即程序的入口
// main(){}方法的开始和结束
// System.out.println("");表示输出内容到屏幕
// ;表示语句结束
public class Hello {
    //编写一个main方法
    public static void main(String[] args){
    System.out.println("hello,world!");
    }
}

一个源文件中最多只有一个public类。其他类的个数不限

编译后每个类都生产一个对应的.class文件

公有类的名称必须是文件名的名称

类名必须以英文字母开头,后接字母数字下划线的组合,习惯以大写字母开头

方法名命名和类一样,但首字母小写

定义常量的时候加上final修饰符这个变量就成了常量

常量定义之后不可以赋值改变常量的值

Java数据类型

 

long型占用8个字节 long age = 10L;

float型占用4个字节 float age = 10.0F

byte数据类型是8位、有符号的,以二进制补码表示的整数;

最小值是-128(-2^7);

最大值是127(2^7-1);

默认值是0;

通常情况下,应该使用double型,应为它比float型更精确

对运算结果是小数的进行相等判断,要小心

应该是以两个数差值的绝对值,在某个精度范围类判断

​​​​​​​

常用转义字符

t 制表位,实现对齐,在控制台可以实现命令对齐

n 换行

r 回车

定义变量时,要遵循作用域最小化原则,尽量将变量定义在尽可能小的作用域,并且,不要重复使用变量名。

面向对象

类是对象的抽象,对象是类的实例。

在Java中,创建一个类,例如,给这个类命名为Person,就是定义一个class:

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

一个class可以包含多个字段(field),属性用来描述一个类的特征。上面的Person类,我们定义了两个属性,一个是String类型的属性,命名为name,一个是int类型的属性,命名为age。因此,通过class,把一组数据汇集到一个对象上,实现了数据封装。

public是用来修饰字段的,它表示这个字段可以被外部访问。

创建实例(对象)

定义了class,只是定义了对象模版,而要根据对象模版创建出真正的对象实例,必须用new操作符。

new操作符可以创建一个实例,然后,我们需要定义一个引用类型的变量来指向这个实例:

Person ming = new Person();

上述代码创建了一个Person类型的实例,并通过变量ming指向它。

注意区分Person ming是定义Person类型的变量ming,而new Person()是创建Person实例。

有了指向这个实例的变量,我们就可以通过这个变量来操作实例。访问实例变量可以用变量.字段,例如:

ming.name = "Xiao Ming"; // 对字段name赋值
ming.age = 12; // 对字段age赋值
System.out.println(ming.name); // 访问字段name

Person hong = new Person();
hong.name = "Xiao Hong";
hong.age = 15;
            ┌──────────────────┐
ming ──────>│Person instance   │
            ├──────────────────┤
            │name = "Xiao Ming"│
            │age = 12          │
            └──────────────────┘
            ┌──────────────────┐
hong ──────>│Person instance   │
            ├──────────────────┤
            │name = "Xiao Hong"│
            │age = 15          │
            └──────────────────┘

两个instance(实例)拥有class定义的name和age属性,且各自都有一份独立的数据,互不干扰。

一个Java源文件可以包含多个类的定义,但只能定义一个public类,且public类名必须与文件名一致。如果要定义多个public类,必须拆到多个Java源文件中。

在OOP(面向对象)中,class和instance是“模版”和“实例”的关系;

定义class就是定义了一种数据类型,对应的instance是这种数据类型的实例;

class定义的field,在每个instance都会拥有各自的field,且互不干扰;

通过new操作符创建新的instance,然后用变量指向它,即可通过变量来引用这个instance;

访问实例字段的方法是变量名.字段名;

指向instance的变量都是引用变量。

public class Haer
{
    public static void main(String[] args)
    {
        //创建Person对象
        //p1对象名
        //new Person()创建的对象空间才是真正的对象
        //对象属性默认值和数组一样且都是引用类型
        //  先声明在创建
        //  Person p1;
        //  p1 = new Person();
        Person p1 = new Person();
        p1.speak();//调用方法
    }
}

class Person
{
    int age;
    String name;
    double sal;
    boolean isPass;

//表示方法公开的 没有返回值 speak()方法名 里面没有行参
    public void speak()
    {
        System.out.println("天下第一!");
    }
}

方法(类似C语言中的函数)

修饰符 方法返回类型 方法名(方法参数列表) {
    若干方法语句;
    return 方法返回值;
}

方法返回值通过return语句实现,如果没有返回值,返回类型设置为void,可以省略return。

调用方法

实例变量.方法名(参数);

public class Main {
    public static void main(String[] args) {
        Person ming = new Person();
        ming.setName("Xiao Ming"); // 设置name
        ming.setAge(12); // 设置age
        System.out.println(ming.getName() + ", " + ming.getAge());
    }
}

class Person {
    private String name;
    private int age;

    public String getName() {
        return this.name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return this.age;
    }

    public void setAge(int age) {
        if (age < 0 || age > 100) {
            throw new IllegalArgumentException("invalid age value");
        }
        this.age = age;
    }
}

 方法不能嵌套定义

public class Haer
{
    public static void main(String[] args)
    {
        A a = new A();
        a.m1();
    }
}

class A
{
    // 同一个类中的方法调用:直接调用即可
    // public void print(int n)
    // {
    //     System.out.print("" + n);
    // }

    // public void sayOk()
    // {
    //     print(10);
    // }
    
    //跨类中的方法 A类调用B类方法:需要通过对象名调用
    public void m1()
    {  
        //创建B类对象,然后在调用方法即可
        B b = new B();
        b.hi();
    }
}

class B
{
    public void hi()
    {
        System.out.println("执行B类的hi()");
    }
}
基本数据类型,传递的是值(值拷贝),形参的改变不影响实参
引用类型传递的是地址(传递也是值,但是值是地址),可以通过形参影响实参!

可变参数

 可变参数用类型...定义,可变参数相当于数组类型:

public class Haer
{
    public static void main(String[] args)
    {
        Methous m = new Methous();
        System.out.println(m.sum(10,1,2,2,2,2,2,2,2));
    }
}
// int...表示接收可变参数,类型是int,即可以接收多个int(0~多)
// 使用可变参数时,可以当作数组来使用,即 nums 可以当作数组
// 遍历nums求和即可
class Methous
{
    public int sum(int...nums)
    {
        int res = 0;
        for(int i = 0; i < nums.length; i++)
        {
            res += nums[i];
        }
        return res;
    }
}

全局变量与局部变量

全局变量(属性/成员变量)可以不赋值直接使用(有默认值),局部变量(方法体)必须先赋值在使用

构造方法/构造器

1.方法名和类相同

2.没有返回值

3.在创建对象时,系统会自动调用该类的构造器完成对象初始化

4.构造器是完成对象的初始化,并不是创建对象

5.在创建对象时,系统自动的调用该类的构造方法

6.如果程序员没有定义构造器,系统会自动给类生成一个默认无参构造器

7.一旦定义了自己的构造器,默认的构造器就覆盖了,就不能使用默认的无参构造器

除非显示定义一下 即 : Cat(){} 声明

[修饰符]方法名(形参列表)
{
    方法体;
}
public class Haer
{
    public static void main(String[] args)
    {
        //当我们创建对象时,直接通过构造器初始化
        Person p = new Person("jack",90);
    }
}
class Person
{
    String name;
    int age;
    // 构造器没有返回值,也不能写void
    // 构造器的名称和类Person一样
    public Person(String pName, int pAge;)
    {
        this.name = pName;
        this.age = pAge;
    }
}

没有在构造方法中初始化字段时,引用类型的字段默认是null,数值类型的字段用默认值,int类型默认值是0,布尔类型默认值是false:

一个构造方法可以调用其他构造方法,这样做的目的是便于代码复用。调用其他构造方法的语法是this(…):

class Person {
    private String name;
    private int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public Person(String name) {
        this(name, 18); // 调用另一个构造方法Person(String, int)
    }

    public Person() {
        this("Unnamed"); // 调用另一个构造方法Person(String)
    }
}

方法/构造方法重载

在一个类中,我们可以定义多个方法。如果有一系列方法,它们的功能都是类似的,只有参数有所不同,那么,可以把这一组方法名做成同名方法。例如,在Hello类中,定义多个hello()方法:

class Hello {
    public void hello() {
        System.out.println("Hello, world!");
    }

    public void hello(String name) {
        System.out.println("Hello, " + name + "!");
    }

    public void hello(String name, int age) {
        if (age < 18) {
            System.out.println("Hi, " + name + "!");
        } else {
            System.out.println("Hello, " + name + "!");
        }
    }
}

这种方法名相同,但各自的参数不同,称为方法重载(Overload)。

方法重载是指多个方法的方法名相同,但各自的参数不同;

重载方法返回值类型应该相同。

一个类可以定义多个不同的构造器,即构造器重载

和使用方法重载一致

public class Main
{
	public static void main(String[] args)
	{
		Person p1 = new Person("haer");
		Person p2 = new Person("sufei",19);
		System.out.println(p1.name);
		System.out.println(p2.name + "t" + p2.age);
	}
}
class Person
{
	String name;
	int age;
	//第一个构造器
	public Person(String pName, int pAge)
	{
		name = pName;
		age = pAge;
	}
	//构造器的重载
	public Person(String pName)
	{
		name = pName;
	}
}

this关键字

1.this关键字可以用来访问本类的属性,方法,构造器

2.this用于区分当前类的属性和局部变量

3.访问成员方法的语法: this.方法名(参数列表)

4.访问构造器语法:this(参数列表);注意只能在构造器中使用(即只能在构造器中访问另外一个构造器,必须放在第一条语句)

5.this不能在类定义的外部使用,只能在类定义的方法中使用

在方法内部,可以使用一个隐含的变量this,它始终指向当前实例。因此,通过this.field就可以访问当前实例的字段。

public class Main
{
	public static void main(String[] args)
	{
		Dog dog = new Dog("haer",19);
		dog.info();
	}
}

class Dog
{
	String name;
	int age;

	public Dog(String name, int age)
	{
		//this.成员变量 就是当前对象的属性
		//哪个调用this this就代表哪个对象
		//this指向自己这个对象
		this.name = name;
		this.age = age;
	}
	
	public void info()
	{
		System.out.println(name + "t" + age);
	}

}

Java定义了一种命名空间,称之为包:package 一个类总是属于某个包 类名(比如Person)只是一个简写,真正的完整类名是包名.类名

包的命名:

只能是字母,数字,下划线,小圆点 (不能用数字开头,不能是关键字或保留字)

命名规范:

小写字母 + 小圆点 + 模块名

eg:com.公司名.项目名.业务模块名

package 的作用是声明当前类所在的包,需要放在类的最上面,一个类中最多只有一句package

import 指令 位置放在package的下面,在类定义前面,可以有多句且没有顺序要求

在定义class的时候,我们需要在第一行声明这个class属于哪个包。

比如小明的 Person.java文件:

package ming; // 申明包名ming

public class Person {
}
package com.hspedu.pkg;
import java.util.Arrays; //导入数组包

public class import01 {
    public static void main(String[] args) {
        int[] arr = {9,8,7,6,5,4,3,2,1};
        Arrays.sort(arr); // 排序                      
        System.out.println(Arrays.toString(arr)); //打印数组内容
    }
}

在Java虚拟机执行的时候,JVM只看完整类名,因此,只要包名不同,类就不同。

位于同一个包的类,可以访问包作用域的字段和方法。不用public、protected、private修饰的字段和方法就是包作用域。例如,Person类定义在hello包下面:

package Hello;

public class Person {
    // 包作用域:
    void hello() {
        System.out.println("Hello!");
    }
}

Main类也定义在Hello包下面:

package Hello;

public class Main {
    public static void main(String[] args) {
        Person p = new Person();
        p.hello(); // 可以调用,因为Main和Person在同一个包
    }
}

package_sample
└─ bin
   ├─ hong
   │  └─ Person.class
   │  ming
   │  └─ Person.class
   └─ com
      └─ jun
         └─ Arrays.class

在一个class中,我们总会引用其他的class。例如,小明的ming.Person类,如果要引用小军的com.jun.Arrays类,他有三种写法:

// Person.java
package ming;

public class Person {
    public void run() {
        com.jun.Arrays arrays = new com.jun.Arrays();
    }
}

第二种写法是用import语句,导入小军的Arrays,然后写简单类名:

/ Person.java
package ming;

// 导入完整类名:
import com.jun.Arrays;

public class Person {
    public void run() {
        Arrays arrays = new Arrays();
    }
}

包的作用:

1.区分名字相同的类

2.当类很多时,可以更好的管理类

3.控制访问范围

*实际上就是创建不同的文件来/目录保存类文件

访问修饰符

公开级别:public

受保护级别:protected 对子类和同一个包中的类公开

默认级别:没有修饰符,向同一个包的类公开

私有级别:private 只有类本身可以访问,不对外公开

在同一类中可以访问 public protected 默认 private修饰的属性或方法

在同一包下,可以访问 public protected 默认 修饰的属性或方法,不能访问private修饰的属性方法

在不同的包下只能访问 public 修饰的属性或方法

封装

(encapsulation)就是把抽象出的数据[属性]和对数据的操作[方法]封装在一起,数据保护在内部,程序的其他部分只有通过被授权的操作[方法],才能对数据进行操作。

public class Encapsulation01{
    public static void main(String[] args){
    Person person = new Person("qqqqq",345,4444,"程序员");
    // person的信息
        System.out.println(person.info());
    }
}
class Person {
    public String name;
    private int age;
    private double salary;
    private String job;

    //无参构造器
    Person(){
    }

    public Person(String name, int age, double salary, String job) {
        //可以将set方法写在构造器中
        setName(name);
        setAge(age);
        setSalary(salary);
        setJob(job);
    }

    public String getName() {
        return name;
    }
    public void setName(String name) {
        // 数据的校验
        if(name.length() >= 0 && name.length() <= 6) {
            this.name = name;
        } else {
            System.out.println("姓名信息错误!");
            this.name = null;
        }
    }

    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        // 数据的校验
        if(age >=1 && age <= 120) {
            this.age = age;
        } else {
            System.out.println("年龄数据错误!");
            this.age = 0;
        }
    }

    public double getSalary() {
        return salary;
    }
    public void setSalary(double salary) {
        this.salary = salary;
    }

    public String getJob() {
        return job;
    }
    public void setJob(String job) {
        this.job = job;
    }
    public String info(){
        return "信息为:" + " 名字 " + name + " 年龄 " + age + " 薪水 " + salary + " 工作 " + job;
    }
}

继承

继承可以解决代码复用,让我们的编程更加靠近人类思维,当多个类存在相同的属性

和方法时,可以从这些类中抽象出父类,在父类中定义这些相同的属性和方法,所有的子类

不需要重新定义这些属性和方法,只需要通过extends来声明继承即可

Java只允许一个class继承自一个类,因此,一个类有且仅有一个父类。只有Object(祖师爷类)特殊,它没有父类。

类似的,如果我们定义一个继承自Person的Teacher,它们的继承树关系如下:

       ┌───────────┐
       │  Object   │
       └───────────┘
             ▲
             │
       ┌───────────┐
       │  Person   │
       └───────────┘
          ▲     ▲
          │     │
          │     │
┌───────────┐ ┌───────────┐
│  Student  │ │  Teacher  │
└───────────┘ └───────────┘

继承基本语法

class 父类{
}

class 子类 ectends 父类{
}

1.子类会自动拥有父类定义的属性和方法

2.父类又叫超类,基类

3.子类又叫派生类

1.子类继承了所有父类的属性和方法 (严禁定义与父类重名的属性方法),非私有的属性和方法可以在子类直接访问,但是私有属性和方法不能在子类直接访问,要通过公共的方法去访问

2.子类必须调用父类的构造器,完成父类的初始化

3.当创建子类对象时,不管使用子类的哪个构造器,默认情况下总会去调用父类的无参构造器如果父类是有参构造器,则必须在子类的构造器中用super() 去指定父类的有参构造器完成对父类的初始化工作,否则编译器不通过。(子类不会继承任何父类的构造方法,子类默认的构造方法是编译器自动生成的,不是继承)

4.如果希望指定去调用父类的某个构造器,则显示的调用一下:super(参数列表)

5.super在使用时,需要放在构造器的第一行,(super() 只能在构造器中使用)

6.super() 和 this() 都只能放在构造器的第一行,因此这两个方法不能存在于一个构造器中

9.子类最多只能继承一个父类(指直接继承),只有 Object 特殊 ,它没有父类 ,即 java 中是单继承机制 


public class ExtendsTheory {
    public static void main(String[] args) {
        Son son = new Son();
        //如果子类有这个属性,并且可以访问,则返回此信息
        //如果子类没有这个属性,就看父类有没有这个属性(如果父类有这个属性,并且可以访问,则返回此信息)
        //如果父类没有这个属性,就继续找上级父类,直到 Object
        System.out.println(son.name + "t" + son.age + "t" + son.hobby);
    }
}

class GrandPa{//父类
    String name = "大头爷爷";
    String hobby = "旅游";
}
class Father extends GrandPa{
    String name = "大头爸爸";
    int age = 39;
}
class Son extends Father{
    String name = "大头儿子";
}
// 思考题目
public class ExtendsExercise01 {
    public static void main(String[] args) {
    B b = new B();
    }
}
class A{

    A(){
        System.out.println("a");
    }
    A(String name){
        System.out.println("a name");
    }
}
class B extends A{
    B(){  //在调用子类的构造器时第一句会默认执行super();对父类完成初始化 这里this()把super()占用了
        this("abc"); // 调用本类的有参构造器
        System.out.println("b");
    }
    B(String name){        //有一个隐藏的super()
        System.out.println("b name");
    }

}

super 关键字

super代表父类的引用,用于访问父类的属性,方法,构造器

// super 是父类的引用 this 是本对象的引用

public class Main{
    public static void main(String[] args) {
        B b = new B();
        b.Hi();
    }
}
class A {
  public int n1 = 100;
  protected int n2 = 200;
  int n3 = 300;
  private int n4 = 400;

  public A(){}
  public A(int n1,int n2, int n3, int n4){}

  public void test100(){
  }
  protected void test200(){
  }
  void test300(){
  }
  private void test400(){
  }
}
class B extends A{
    //访问父类的属性,但不能访问 private 的属性 super.属性名
    public void Hi(){
        System.out.println(super.n1 + " " + super.n2 + " " + super.n3);
    }
    //访问父类的方法,但不能访问 private 的方法 super.方法名(参数列表)
    public void Hi0(){
       super.test100();
       super.test200();
       super.test300();
    }
    public B(){
        super(1,1,1,1);
    }
}

1.调用父类的构造器的好处(父类字段由父类初始化,子类的字段由子类初始化)

2.当子类中有和父类中的 字段/方法 重名时,为了访问父类的字段,必须通过super,如果没有重名,使用 super, this 直接访问是一样的效果。

public class Main{
    public static void main(String[] args) {
        B b = new B();
        b.sum();
    }
}
class A {  // 父类
  public int n1 = 100;
  protected int n2 = 200;
  int n3 = 300;
  private int n4 = 400;

  public void cal(){
      System.out.println("A类的cal()方法");
  }
}
class B extends A{  //子类
    public int n1 = 888;
    public void cal(){
        System.out.println("B类的cal()方法");
    }
    public void sum(){
        System.out.println("B类的sum()");
        // 希望调用父类 A 的 cal() 方法
        // 因为B类没有cal()方法
        // 找cal()方法时 先找本类,如果有,并且可以调用,则调用。如果没有则找父类(如果有并且可以调用,则调用)
        // 如果父类没有,则继续找父类的父类 直到 Object 规则一致
        // cal();
        this.cal(); // 等价 cal()
        // super.cal(); // 直接到父类中去找 cal() 方法

        // 访问属性的规则 和方法一致
        System.out.println(n1);
        System.out.println(this.n1);
        System.out.println(super.n1);
    }
}

这是因为在Java中,任何class的构造方法,第一行语句必须是调用父类的构造方法。如果没有明确地调用父类的构造方法,编译器会帮我们自动加一句super();,所以,Student类的构造方法实际上是这样:

class Student extends Person {
    protected int score;

    public Student(String name, int age, int score) {
        super(); // 自动调用父类的构造方法
        this.score = score;
    }
}

因此我们得出结论:如果父类没有默认的构造方法,子类就必须显式调用super()并给出参数以便让编译器定位到父类的一个合适的构造方法。

这里还顺带引出了另一个问题:即子类不会继承任何父类的构造方法。子类默认的构造方法是编译器自动生成的,不是继承的。

方法重写/覆盖

方法覆盖(重写)就是子类有一个方法,和父类的某个方法的名称,返回类型,参数一样,那么就说子类的这个方法覆盖了父类的那个方法

方法重写的原理:子类中的方法和父类中方法名字相同,对象在调用的时候默认会从子类中开始查找,找到后就调用,然后不会再往父类继续查找

子类的方法的参数,方法名称,要和父类方法的参数,方法名称完全一致

public class Main{
    public static void main(String[] args) {
        Dog dog = new Dog();
        dog.cry();
    }
}
class Animal { //父类
    public void cry() {
        System.out.println("动物呼唤!");
    }
}
class Dog extends Animal{ // 子类
    // Dog 的 cry方法和 Animal 的 cry方法定义的形式一样 (名称,返回类型,参数)
    // 这时我们就说 Dog 的 cry 方法,重写了 Animal 的 cry 方法
    public void cry() {
        System.out.println("小狗汪汪叫~");
    }
}

子类方法的返回类型和父类方法返回类型一样,或者是父类返回类型的子类 比如 父类的返回类型 是 Object ,子类方法返回类型是 String

子类方法不能缩小父类方法的访问权限(可以扩大)

public class Main{
    public static void main(String[] args) {
        Dog dog = new Dog();
        dog.cry();
    }
}
class Animal { //父类
    public void cry() {
        System.out.println("动物呼唤!");
    }
    // 返回值类型为父子关系
    public Object m1() {
        return null;
    }
}
class Dog extends Animal{ // 子类
    // Dog 的 cry方法和 Animal 的 cry方法定义的形式一样 (名称,返回类型,参数)
    // 这时我们就说 Dog 的 cry 方法,重写了 Animal 的 cry 方法
    public void cry() {
        System.out.println("小狗汪汪叫~");
    }
    public String m1() {
        return null;
    }
    // 子类方法不可以缩小父类方法的访问权限
//    private void cry() {
//        System.out.println("小狗汪汪叫~");
//    }
}

多态

多态是指,针对某个类型的方法调用,其真正执行的方法取决于运行时期实际类型的方法。

// 重写和重载体现多态
public class Main {
    public static void main(String[] args) {
        // 方法重载体现多态
        A a = new A();
        // 传入不同的参数,就会调用不同的sum方法,体现多态
        System.out.println(a.sum(10,20));
        System.out.println(a.sum(10,20,30));
        // 方法重写体现多态
        B b = new B();
        a.say();
        b.say();
    }
}
class B {
    public void say() {
        System.out.println("B say() 方法别调用...");
    }
}
class A extends B {

    public int sum(int n1, int n2) {
        return n1 + n2;
    }
    public int sum(int n1, int n2, int n3) {
        return n1 + n2 + n3;
    }
    public void say() {
        System.out.println("A say() 方法别调用...");
    }
}

多态的特性就是,运行期才能动态决定调用的子类方法。对某个类型调用某个方法,执行的实际方法可能是某个子类的覆写方法

Java的方法调用总是作用于运行类型对象的实际类型,这种行为称为多态;

多态的前提条件:两个对象 (类) 存在继承关系

多态的向上转型

    父类的引用指向了子类的对象

    父类类型 引用名 = new 子类类型();

    编译类型看左边, 运行类型看右边

public class Main {
  public static void main(String[] args) {
  // 向上转型:父类的引用指向了子类的对象
  Animal animal = new Cat();
  animal.eat();
  // Object obj = new Cat(); // Objict 也是 Cat 的父类
  // 向上转型以后 可以访问父类的属性和方法(在访问范围之内)
  // 但是不能访问子类特有的属性和方法, 在编译阶段,能调用哪些成员,由编译类型决定
  System.out.println(animal.name);
  animal.show();
 //  animal.catage;  error
 //  animal.catchMouse(); erroe
 // 最终运行效果看子类(运行类型)的具体表现,即调用方法时,按照从子类(运行类型)开始查找方法,然后调用
  }
}
class Animal {
  String name = "动物";
  int age = 10;
  public void sleep() {
    System.out.println("睡");
  }
  public void run() {
    System.out.println("跑");
  }
  public void eat() {
    System.out.println("吃");
  }
  public void show() {
    System.out.println("你好,世界!");
  }
}
class Cat extends Animal{
  public int catage = 100;
  public void eat() { //方法重写
   System.out.println("猫吃鱼");
  }
  public void catchMouse() { //Cat特有方法catchMouse()
    System.out.println("猫抓老鼠");
  }
}

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/777309.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号