JAVA基础入门

编程基础

基本语法

基本格式

1
2
3
修饰符 class 类名{
程序代码
}
  • 结构定义语句用于声明一个类或方法
  • 功能执行语句用于实现具体得功能,且最后要用 ;结束

注意:

  1. JAVA严格区分大小写
  2. 一个连续得字符串不能分成两行书写,但可以分成两个字符串用+连接

例子

1
2
3
4
5
6
7
package 包名;

public class 文件名 {
public static void main(String[] args){
System.out.println("啦啦");
}
}

注释

1
2
3
4
5
6
7
8
9
10
11
12
13
单行注释:
//int a = 0;

多行注释:
/* int a = 0;
int b = 1; */

文档注释(可以使用javadoc命令提取出来):
/**
*@author nacy
*@version 1.0
**/

标识符

标识符可以由字母、数字、下画线_和美元符号$组成,但标识符不能以数字开头,不能是JAVA中得关键字。

规则:

  • 包名所有字母小写:cn.itcast.test
  • 类名和接口名每个单词首字母大写:ArrayList
  • 常量名所有字母大写,单词间下画线连接:DAY_OF_MONTH
  • 变量名和方法名第一个单词首字母小写,其他首字母大写:lineNumber
  • 使用有意义的英文单词定义:password

关键字

  • 关键字小写
  • 关键字不命名标识符
  • 保留关键字const,goto,无意义但不能作标识符
  • true,false,null不属于关键字也不作为标识符

常量

  • 整形常量
    • 二进制(0b/0B开头)
    • 八进制(0开头)
    • 十进制
    • 十六进制(0x/0X开头)
  • 浮点数常量
    • 单精度浮点数float (后缀-F/-f:2e3f)
    • 双精度浮点数**double **(后缀-D/-d,不加后缀:3.6d)
  • 字符常量
    • '一个字符'
    • Unicode字符集:’\u0000’空白字符
  • 字符串常量
    • "一串连续的字符"
  • 布尔常量
    • true 和 false
  • null常量
    • null,表示对象的引用为空

变量

数据类型

  • 基本数据类型
    • 数值型
      • 整数类型
        • 字节型 byte(1B)
        • 短整型 short(2B)
        • 整形 int(4B)
        • 长整型 long(8B,后缀-L/-l)
      • 浮点数类型
        • float(4B,,后缀-F/-f)
        • double(8B,后缀-D/-d,不加后缀)
    • 字符型 char
    • 布尔型 boolean
  • 引用数据类型

类型转换

  • 自动类型转换/隐式类型转换

  • 强制类型转换/显式类型转换

    byte b = (byte)num;

作用域

以大括号包围的为范围

运算符

算术运算符

+3,-3,+,-,*,/.%(正负取决于左边的数),a++,++a,a--,--a

赋值运算符

=,+=,-=,*=,/=,%=

比较运算符

==,!=,<,>,<=,>=

逻辑运算符

&与,|或,^异或,!非,&&短路与,||短路或

优先级

image-20220923215023439

结构语句

选择结构语句

  • if条件语句

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    if(a >= 100)
    {
    b = 100;
    }
    else if(a < 100 && a >= 60)
    {
    b = 60;
    }
    else
    {
    b = 0;
    }
  • 三元运算符

    1
    2
    a>=100?b=100:(a<100&&a>=60?b=60:b=0);
    -> a>=100?b=100:a<100&&a>=60?b=60:b=0;
  • switch条件语句

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    switch(a){
    case 100:
    b = 100;
    break;
    case 60:
    b = 60;
    break;
    default
    b = 0;
    break;
    }

循环结构语句

  • while循环语句

    1
    2
    3
    4
    int x = 4;
    while(x <= 4){
    x--;
    }
  • do…while循环语句

    1
    2
    3
    4
    int x = 5;
    do{
    x--;
    }while(x <= 4);
  • for循环语句

    1
    2
    3
    4
    int x = 4;
    for(int i=0; i<=4; i++){
    x--;
    }
  • 跳转语句

    • break语句(直接结束当前循环)
    • continue语句(跳过循环中的一次)

方法

语法格式

1
2
3
4
修饰符 返回值类型 方法名(参数类型 参数1, 参数类型 参数2, ...){
执行语句
return 返回值;
}
  • 修饰符:static, final…

方法重载

相同的方法名,以不同参数区分不同方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package exp02;

public class demo02 {
//Java方法重载
public static void main(String[] args){
int sum1 = add(1,2);
int sum2 = add(1,2,3);
double sum3 = add(1.2,2.3);

System.out.println("sum1="+sum1);
System.out.println("sum2="+sum2);
System.out.println("sum3="+sum3);
}

public static int add(int x, int y){
return x+y;
}
public static int add(int x, int y, int z){
return x+y+z;
}
public static double add(double x, double y){
return x+y;
}
}

数组

一维数组

  • 法一

    1
    2
    3
    int[] x;
    x = new int[100];//变量初始值默认都为0
    x[0] = 11;
  • 法二

    1
    2
    int[] x = new int[5];
    x[0] = 88;
  • 法三

    1
    2
    int[] x = {1,2,3,4,5};
    int[] x = new int[5] {1,2,3,4,5};

arr = null表示没有指向任何数组,通过该变量访问数组元素会出现空指针异常

arr.length获得数组长度,即元素个数

二维数组

  • 法一

    1
    int[][] x = new int[3][4
  • 法二

    1
    2
    int[][] x = new int[3][];
    x[0] = new int[] {1,2,3};
  • 法三

    1
    int[][] x = {{1,2},{1,2,3},{1,2,3,4}};

排序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
package exp02;

public class demo01 {
public static void main(String[] args){
//使用循环语句实现自然数1˜99的遍历
int x=1;
while(x<101){
System.out.println(x++);
}
//在遍历过程中,通过条件判断当前遍历的数是否为奇数,如果是累加,否则不加
int sum = 0;
for(int i=1; i<101; i++){
if(i%2!=0){
sum += i;
}
}
System.out.println(sum);//2500
//使用任意算法编写程序,实现对数组{25,24,12,76,101,96,28}的降序排列
//选择排序
int[] arr = {25,24,12,76,101,96,28};
int maxi;
for(int i=0; i<arr.length-1; i++){
maxi = i;
for(int j=i+1; j<arr.length; j++){
if(arr[maxi]<arr[j])maxi=j;
}
if(maxi != i){
int temp = arr[maxi];
arr[maxi] = arr[i];
arr[i] = temp;
}
}
for(int i=0; i<arr.length; i++)
System.out.println(arr[i]);//咋样实现不换行输出
//冒泡排序
int[] arr0 = {25,24,12,76,101,96,28};
for(int i=1; i<arr0.length; i++){
for(int j=0; j<arr0.length-i; j++){
if(arr0[j]<arr0[j+1]){
int temp = arr0[j];
arr0[j] = arr0[j+1];
arr0[j+1] = temp;
}
}
}
for(int i=0; i<arr0.length; i++){
System.out.println(arr0[i]);
}
}

面向对象(上)

面向对象

面向对象和面向过程:

  • 面向对象的思想:程序中使用对象映射现实中的事物,使用对象的关系描述事物之间的联系
  • 面向过程的思想:通过分析得出解决问题所需的步骤,然后写出函数将步骤实现,使用时依次调用

面向对象的特性:

  • 封装性
  • 继承性
  • 多态性

类与对象

类和对象是最基本、最重要的单元。类表示某类群体的一些基本特征的抽象,对象表示一个个具体的事物。

类用于描述多个对象的共同特征,它是对象的模板。对象用于描述现实中的个体,它是类的实例。对象是根据类创建的,一个类可以对应多个对象。比如车是一个类具有所有车的共性,出租车、卡车、货车是对象还具有特性。

类的定义

类是对象的抽象,用于描述一组对象的共同特征和行为。

类中可以定义成员变量和成员方法。成员变量,又称对象的属性,用于描述对象的特征。成员方法,简称方法,用于描述对象的行为。

1
2
3
4
5
6
7
8
9
10
11
//定义Student类:class+类名
class Student{
//属性/成员变量
String name;
int age;
String sex;
//方法/成员方法
void read(){
System.out.println("name:"+name);
}
}

注意:类中的成员变量和成员方法中的局部变量可以同名,但方法中变量名访问的是局部变量而不是成员变量。

对象的创建与使用

要想要使用一个类,必须创建该类的对象。new关键字创建对象:

  • 形式一

    1
    2
    3
    4
    5
    6
    //1.声明对象:类名 对象名 = null;
    //声明一个Student类的变量stu(栈内存)
    Student stu = null;
    //2.实例化对象:对象名 = new 类名();
    //运算符=将新创建的实例对象地址赋值给变量stu(堆内存)
    stu = new Student();
  • 形式二

    1
    Student stu = new Student();

注意:对象名stu保存在栈内存中,而对象属性信息保存在对应的堆内存中。new关键字创建的对象在堆内存中分配空间。

1
2
3
4
5
对象使用
//对象名.属性名
stu.name = "小华";
//对象名.方法名
stu.read();

对象的引用传递

类属于引用数据类型,引用数据类型的内存空间可以同时被多个栈内存引用。所谓的引用传递,就是将一个堆内存空间的使用权分配给多个栈内存空间使用,每个栈内存空间都可以修改堆内存空间的内容,即:多个变量被赋予了同一个实例对象地址(无数的小明……),一个变量把内容修改了所有变量都修改(一个小明剪了平头,所有其他小明同时变成平头)。

1
2
3
4
5
6
7
8
9
10
11
12
Student stu = new Student();
Student stu1 = null;
Student stu2 = null;
stu1 = stu;
stu2 = stu;
stu.name = "光头强";
stu1.name = "熊大";
stu2.name = "熊二";
stu.read();
stu1.read();
stu2.read();
//结果是都输出:name:熊二

注意:一个栈内存空间只能指向一个堆内存空间。如果想要再指向其他堆内存空间,就必须先断开已有的指向,才能分配新的指向。

4种访问控制权限

4种访问控制权限按级别由低到高:

  • private:私有访问权限。修饰类的属性和方法,也可以修饰内部类。类的成员只能在本类中访问。
  • default:默认访问权限。表现形式:类中属性或方法无任何访问权限声明。类的成员可以被本包中的其他类访问,但不能被其他包的类访问。
  • protected:受保护的访问权限。类的成员只能被本包以及不同包的子类访问
  • public:公共访问权限。类的成员可以在所有类中被访问,不限制包。

注意:外部类的访问权限只能是public和default。局部成员是没有访问控制权限。

封装性

封装是指将类的实现细节包装、隐藏起来的方法。

为了避免信息错误(age = -18),设计类时,应该对成员变量的访问做出一些限制,不允许外界随意访问,这就需要实现类的封装。

封装的具体实现过程:

  • 定义一个类时,将类中的属性私有化(private关键字)
  • 定义public修饰的公有方法来访问私有变量,包括获取属性值的getter方法和设置属性值得setter方法。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
package exp02;

//个人简历的封装类
class Resume{
//属性私有化
private String name;
private int age;
//getter方法
public String getName(){
return name;
}
public int getAge(){
return age;
}
//setter方法
public void setName(String name){
this.name = name;
}
public void setAge(int age){
if(age<18){
System.out.println("请输入不小于18岁的年龄!");
//int变量初始值默认为0
}else{
System.out.println("年龄不小于18岁,输入正确!");
this.age = age;
}
}
public void introduce(){
System.out.println("自我介绍");
System.out.println("姓名:"+name+" 年龄:"+age);
}
}

public class demo04 {
public static void main(String[] args){
Resume re = new Resume();
re.setName("二狗子");
re.setAge(-18);
re.introduce();
Resume re1 = new Resume();
re1.setName("大肥羊");
re1.setAge(19);
re1.introduce();
}
}

构造方法

如果需要在实例化对象时为这个对象的属性赋值,可以通过构造方法实现。构造方法,又称为构造器,是类的一个特殊成员方法,在类实例化对象时自动调用

构造方法的定义

1
2
3
4
5
6
7
8
9
10
11
12
class Student{
String name;
int age;
String sex;
public Student(){
System.out.println("调用了无参构造方法");
}
public Student(String name){
this.name = name;
System.out.println("调用了有参构造方法实现对属性的赋值");
}
}

注意:

  • 构造方法的名字要与类名一致
  • 构造方法名前不能有任何返回值类型声明,也不能在构造方法中return值,但可以单return作为方法结束。
  • 构造方法的调用在关键字new实例化对象的时候
  • 有参构造方法可以实现方法重载(参数类型或个数不同)
  • 每个类至少有一个构造方法。如果没有定义构造方法,系统会自动创建一个默认构造方法(无参无代码)。但类定义了构造方法,系统不会提供默认构造函数。
  • 可以使用this在构造方法中调用其他构造方法(详见this关键字调用构造方法)

this关键字

调用本类中的属性

当成员变量和局部变量发生重名问题时,需要用this关键字分辨成员变量和局部变量。

1
2
3
4
5
6
7
8
9
10
class Student{
String name;
int age;
String sex;
public Student(String name,int age,String sex){
this.name = name;
this.age = age;
this.sex = sex;
}
}

调用成员方法

1
2
3
4
5
6
7
8
class Student{
public void word(){
System.out.println("Hello world!");
}
public void read(){
this.word();//this可以省略不写
}
}

调用构造方法

构造方法在实例化对象时被JAVA虚拟机自动调用,在程序中不能像成员方法那样调用构造函数。但可以在一个构造方法中使用“this(…)”调用其他构造方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
class Student{
String name;
int age;
String sex;
public Student(){
System.out.println("调用了无参构造方法");
}
public Student(String name){
this();//调用无参构造方法
this.name = name;
System.out.println("调用了有参构造方法实现对属性的赋值");
}
}

注意:

  • 只能在构造方法中使用this调用其他的构造方法
  • 在构造方法中,使用this调用其他的构造方法的语句必须位于第一行,且只能出现一次
  • 不能在类中使用this互相调用

代码块

{}括起来的一段代码

普通代码块

一对{}就是一个代码块,main方法中定义了一个局部代码块,实现“分隔”,起到限定作用域的作用,互不影响。

1
2
3
4
5
6
7
8
9
10
public class demo01{
public static void main(String[] args){
{
int age = 18;
System.out.println("普通代码块中age="+age);
}
int age = 30;
System.out.println("main方法中age="+age);
}
}

构造块

直接在类中定义的代码块

1
2
3
4
5
6
7
8
class Student{
{
System.out.println("调用了构造块");
}
public Student(){
System.out.println("调用了无参构造方法");
}
}

结论:

  • 构造块和构造方法同级,但实例化对象时,构造块比构造方法先执行

静态代码块

1
2
3
4
5
6
7
8
9
class Student{
String name;
int age;
String sex;
static String school = "A大学";
public Student(String name){
this.name = name;
}
}

同步代码块

多线程部分讲解

static关键字

用于修饰类的成员,如成员变量、成员方法、代码块等。

如果一个方法与他所在类的实例对象无关,那么它就应该是静态的,而不应该把它写成实例方法。所以所有的实例方法都与实例有关,既然与实例有关,那么创建实例就是必然的步骤。

静态属性

静态属性,又称全局属性,可以使用类名直接访问。

1
2
3
4
5
6
class Student{
static String school = "A大学";
public void read(){
System.out.println("school="+school);
}
}
1
Student.school = "B大学";

注意:

  • static关键字将school属性变为公共属性,只分配一块内存空间,为Student类所有对象共享。
  • 某个对象进行school属性的修改,全部对象的school属性都被修改。
  • static只能修饰成员变量,不能修饰局部变量

静态方法

实现不创建对象的情况下,通过类名直接调用方法。(正常情况下需要将类实例化才能调用成员方法)

1
2
3
4
5
6
7
8
9
10
11
12
class Student{
static String school = "A大学";
public static String getSchool(){
return school;
}
public static void setSchool(String s){
school = s;
}
public void read(){
System.out.println("school="+school);
}
}
1
Student.setSchool("B大学");

注意:

  • 静态方法只能访问静态成员。
  • 非静态成员需要先创建对象才能访问,即对象创建后非静态成员才会分配内存。
  • **this 关键字不能用于引用类的静态成员。**这是因为this 关键字指向类的当前对象 ,并且静态成员不需要调用任何对象。可以直接访问类的静态成员,而无需在Java中创建对象。
  • 静态方法不需要通过它所属的类的任何实例就可以被调用,因此在静态方法中不能使用this关键字,也不能直接访问所属类的实例变量和实例方法,但是可以直接访问所属类的静态变量和静态方法(静态方法只能调用静态变量)。

静态代码块

1
2
3
4
5
6
7
8
9
10
11
12
13
class Student{
static String school;
{
System.out.println("调用了构造块");
}
static{
school = "A大学";
System.out.println("调用了静态代码块");
}
public Student(){
System.out.println("调用了无参构造方法");
}
}

注意:

  • 当类被加载时,静态代码块就会执行。由于类只加载一次,所以静态代码块只执行一次(类第一次使用)
  • 执行顺序:静态代码块->构造代码块->构造方法

例子

面向对象(下)

继承

概念:

  • 继承描述的是事物间的从属关系,通过继承可以使多种事物之间形成一种关系体系。

  • JAVA类的继承是指在一个现有类的基础上构建一个新的类。

  • 声明一个类继承另一个类,使用extends关键字

    1
    2
    3
    4
    5
    6
    class 父类{
    ...
    }
    class 子类 extends 父类{
    ...
    }

特点:

  • 构建的新类叫子类,现有的类叫父类
  • 子类自动继承父类的属性和方法,子类只能访问父类中用publicprotected修饰的属性和方法
  • 类只支持单继承,不允许多继承但允许多层继承,即:一个人只能有一个爸爸,但可以有好多辈祖宗,爸爸可以有好多娃子

注意:there is no default constructor available in …

  • 这个错误是由于继承引起的,原因是子类里写了并且使用了无参的构造方法但是它的父类(祖先)中却至少有一个是没有无参构造方法的,就会出现这个问题。原因:

    • 1.一个类如果显式的定义了带参构造函数,那么默认无参构造函数自动失效 。我们都知道一个类如果没有定义构造函数,那么会有一个默认的无参构造函数供你调用就是MyClass()。 但是如果你定义了一个带参构造函数,而没有显式的定义无参构造函数,那么无参构造函数就被隐藏了。

    • 2.一个类只要有父类,那么在它实例化的时候,一定是从顶级的父类开始创建。对于Java来说要一直追述到Object 祖宗(Object)-> 曾爷爷 -> 爷爷 -> 父亲 -> me

      这个思维很自然,没有祖宗,何来后代?祖宗的一些东西都没准备好,后代怎么继承去用?

  • 也就是说当你用子类的无参构造函数创建子类对象时,会去先递归调用父类的无参构造方法,这时候如果某个类的父类没有无参构造方法就会出错啦~

  • 要么就是父类使用了有参构造,要么让父类再写个无参构造,要么子类继续写有参构造

继承的创建和使用

1
2
3
4
5
6
7
8
9
10
//父类
class Student{
private String name;
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
1
2
3
4
//子类
class Pupil extends Student{
//...
}
1
2
3
4
//main函数
Pupil p = new Pupil();
p.getName("小王");
System.out.println("姓名:"+this.getName());

方法重写

  • 子类中重写父类,即子类对父类继承的方法进行一些修改。

  • 子类重写的方法需要和父类中被重写的方法具有相同的方法名、参数列表以及返回值类型。

    1
    2
    3
    4
    5
    6
    //父类
    class Student{
    public void mode(){
    System.out.println("学生的就读方式");
    }
    }
    1
    2
    3
    4
    5
    6
    //子类
    class Pupil extends Student{
    public void mode(){
    System.out.println("学生的就读方式为:走读");
    }
    }
    1
    2
    3
    //main函数
    Pupil p = new Pupil();
    p.mode();

注意:重写时,不能使用比父类的方法更严格的访问权限

super关键字

  • 子类中使用super关键字访问父类成员,例如:子类重写父类的方法后,子类对象将无法访问父类中被子类重写过的函数,使用super关键字可以访问父类成员

  • super关键字可以在子类中访问父类的非私有方法、非私有属性和构造方法。

    1
    2
    3
    4
    5
    6
    //父类
    class Student{
    public void mode(){
    System.out.println("学生的就读方式为:");
    }
    }
    1
    2
    3
    4
    5
    6
    7
    //子类
    class Pupil extends Student{
    public void mode(){
    super.mode();
    System.out.println("走读");
    }
    }

**注意:**super关键字调用父类构造方法的代码必须位于子类构造方法的第一个行,并且只能出现一次,所以this和super不能同时出现

final关键字

  • 当父类的成员不希望被子类重写时,可以在声明父类的成员时使用final关键字修饰。
  • final关键字修饰类、属性、方法

注意:

  • 修饰的类不能是子类,且不可以被继承和派生子类
  • 修饰的方法不能被子类重写
  • 修饰的变量是常量,只能在声明时被赋值一次且后续不可修改
    • final声明变量,变量名称要求全部大写
    • 变量使用public static final声明,为全局常量
1
2
3
4
5
6
7
8
9
//修饰类
final class Student{
//修饰变量
public static final String school = "曲阜师范大学";
//修饰方法
public final void type(){
System.out.println("全日制学生");
}
}

抽象类和接口

抽象类

定义一个类中,有些用于描述类的行为特征而定义出的成员方法,因为方法的实现方式无法确定,所以使用abstract关键字修饰的抽象方法来实现,抽象方法在定义时不需要实现方法体。

1
2
3
4
//父类:抽象类
abstract class Student{
abstract void show();
}
1
2
3
4
5
class Undergraduate extends Student{
void show(){
System.out.println("毕业生")
}
}

注意:

  • 抽象方法和类必须使用Abstract关键字修饰,包含抽象方法的类必须是抽象类(不能直接创建对象,可以使用匿名内部类完成抽象方法重写)
  • 抽象方法在抽象类中定义时不需要实现方法体,抽象方法不能使用private关键词修饰
  • 非抽象类继承抽象类后必须重写全部抽象方法。

接口

接口是抽象类衍生的一个概念(面向接口编程:将程序的不同的业务逻辑分离以接口的形式对接不同的业务模块。接口中不实现任何业务逻辑,业务逻辑实现和修改由接口的实现类完成。)。
接口是一种用来定义程序的协议,它用于描述类或结构的一组相关行为。使用接口的目的是克服单继承的限制,因为一个类只有一个父类,而一个类可以同时实现多个父接口。接口由全局常量、抽象方法、默认方法、静态方法组成,都是默认public访问权限(可省略)。

  • 接口声明(interface关键字)

    1
    2
    3
    4
    5
    6
    [public] interface 接口名 [extends 接口1,接口2,...]{
    [public static final] double Pi = 3.1415926;
    [public abstract] double area(double x);
    [public] static 返回值数据类型 方法名(参数列表){}
    [public] default 返回值数据类型 方法名(参数列表){}
    }
  • 接口实现类定义(implements关键字)

    1
    2
    3
    4
    5
    6
    修饰符 class 类名 [extends 父类名] implements 接口1,接口2,...{
    public double area(double x) {
    return x*x;
    }
    ...
    }

注意:

  • 接口是抽象类衍生的概念。使用接口的目的是克服单继承限制,一个类可以实现多个父接口。
  • 接口不能实例化,通过接口实现类的实例化对象进行方法调用。接口的访问权限都为public(可省略),可以定义全局变量(public static final)、抽象类(public abstract)、默认方法(public default)、静态方法(public static)。
  • 接口可以继承多个接口,但不能继承抽象类。

例子

设计一个Shape接口和它的两个实现类Square和Circle。要求如下:

① Shape接口中有一个抽象方法area(),方法接收有一个double类型的参数,返回一个double类型的结果。

② Square和Circle中实现了Shape接口的area()抽象方法,分别求正方形和圆形的面积并返回。

③ 在测试类中创建Square和Circle对象,计算边长为2的正方形面积和半径为3的圆形面积。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
interface Shape{
public double area(double x);
}
class Square implements Shape{
public double area(double x) {
return x*x;
}
}
class Circle implements Shape{
final double Pi = 3.1415926;
public double area(double x) {
return Pi*x*x;
}
}

public class demo01 {
public static void main(String[] args){
Square s = new Square();
Circle c = new Circle();
System.out.println("s.area(2): "+s.area(2));
System.out.println("c.area(3): "+String.format("%.2f",c.area(3)));
}
}

多态

多态是指不同类的对象在调用同一个方法时表现出的多种不同行为(重写)或在同一方法中由于参数类型/个数不同而导致执行效果不同的现象(重载),即实现同一方法名调用出不同行为。多态的两种形式:

  • 方法的重载
  • 对象的多态(方法的重写)

对象类型的转换

使用对象类型转换解决继承中的多态问题。

  • 向上转型:子类对象 \rightarrow父类对象

    父类对象想调用子类重写的父类方法为对象向上转型,但父类不能调用子类中定义的方法。向上转型,程序会自动完成。该方式可以实现新增子类,从而在子类中对父类的功能进行扩展,而不用修改父类的代码,保证程序的安全性。

    1
    Animal an1 = new Cat("阳阳",2);
  • 向下转型:父类对象 \rightarrow子类对象

    向下转型一般用于向上转型后想调用子类定义的方法。对象进行向下转型前必须先进行向上转型,否则异常。

    1
    2
    Animal an2 = new Dog("土豆",3);
    Dog dog = (Dog) an2;

例子

参照、优化教材P130 Exmaple14要求如下:

① Animal有两个私有属性name(String),age(int)。

② Cat继承Animal类有一个方法action(),输出“猫捉老鼠”。

Dog继承Animal类有一个方法eat(),输出“狗啃骨头”。

③ 编写测试类,实现功能:当是Cat对象时输出基本信息加“喵喵”及“猫捉老鼠”;当是Dog对象时输出基本信息加“汪汪”及“狗啃骨头”

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
package package01;

abstract class Animal{
private String name;
private int age;

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

public int getAge() {
return age;
}

public String getName() {
return name;
}

abstract void shout();
public void action(){

}
public void eat(){

}
}
class Cat extends Animal{
public void shout(){
System.out.println("喵喵喵……");
}
public void action() {
System.out.println("猫捉老鼠");
}
Cat(String name, int age){
setAge(age);
setName(name);
}
public void info(){
System.out.println("姓名:"+super.getName()+" 年龄:"+super.getAge());
shout();
action();
}
}
class Dog extends Animal{
public void shout(){
System.out.println("汪汪汪……");
}
public void eat(){
System.out.println("狗啃骨头");
}
Dog(String name, int age){
setAge(age);
setName(name);
}
public void info(){
System.out.println("姓名:"+super.getName()+" 年龄:"+super.getAge());
shout();
eat();
}
}

public class demo01 {
public static void main(String[] args){
Animal an1 = new Cat("阳阳",2);
Cat cat = (Cat) an1;
Animal an2 = new Dog("土豆",3);
Dog dog = (Dog) an2;
cat.info();
dog.info();
}
}

Object类

Object类常用方法

内部类

四种内部类的特点

关键字总结

关键字 含义 备注
class关键字 定义一个类 class 类名{}
new关键字 创建一个对象 类名 对象名=new 类名();
private关键字 私有访问权限,类内访问
default关键字 默认访问权限,包内访问
protected关键字 受保护访问权限,本包和不同包的子类访问
public关键字 公共访问权限,全局范围
this关键字 成员变量和局部变量发生重名问题
一个构造方法中使用“this(…)”调用其他构造方法
调用语句必须位于第一行,且只能出现一次
不能在类中使用this互相调用
static关键字 静态属性,又称全局属性,可以使用类名直接访问
实现不创建对象的情况下,通过类名直接调用方法
静态方法只能访问静态成员
this 关键字不能用于引用类的静态成员
静态代码块只执行一次,首先执行
extends关键字 声明一个类继承另一个类
super关键字 子类访问父类成员 父类的非私有方法、非私有属性和构造方法
final关键字 不被子类重写 变量使用public static final声明,为全局常量
abstract关键字 抽象类和抽象方法
interface关键字 接口声明
implements关键字 接口实现类的定义