文章内容输出来源:拉勾教育大数据开发高薪训练营
本篇文章是java学习课程中的一部分笔记。
本博文主要是记录一些基础的知识点,通过实操更容易理解
面向对象编程的概念
• 万物皆对象。
• 面向对象指以属性和行为的观点去分析现实生活中的事物。
• 面向对象编程指先以面向对象的思想进行分析,然后使用面向对象的编程语言 进行表达的过程。
• 面向对象编程是软件产业化发展的需求。
• 理解面向对象的思想精髓(封装、继承、多态),至少掌握一种编程语言。
类和对象的概念• 对象主要指现实生活中客观存在的实体,在Java语言中对象体现为内存空 间中的一块存储区域。
• 类简单来就是“分类”,是对具有相同特征和行为的多个对象共性的抽象描 述,在Java语言中体现为一种引用数据类型,里面包含了描述特征/属性 的成员变量以及描述行为的成员方法。
• 类是用于构建对象的模板,对象的数据结构由定义它的类来决定。
类的定义• class 类名 {
类体;
}
• 注意:
通常情况下,当类名由多个单词组成时,要求每个单词首字母都要大写。
例:
class Person { }
成员变量的定义
• class 类名 {
数据类型 成员变量名 = 初始值;
}
• 注意: 当成员变量由多个单词组成时,通常要求从第二个单词起每个单词的首 字母大写 。
对象的创建class Person { String name; }
• new 类名(); 例:new Person();
• 注意:
a.当一个类定义完毕后,可以使用new关键字来创建该类的对象,这个过程叫做类的实例化。
b.创建对象的本质就是在内存空间的堆区申请一块存储区域, 用于存放该对象独有特征信息。
引用的定义• 基本概念
a.使用引用数据类型定义的变量叫做引用型变量,简称为"引用"。
b.引用变量主要用于记录对象在堆区中的内存地址信息,便于下次访问。
• 语法格式
类名 引用变量名;
引用变量名.成员变量名;
Person p = new Person(); p.name = "张飞"; System.out.println(p.name);
案例题目• 编程实现Point类的定义,特征有:横纵坐标(整数),要求在main方法中 声明Point类型的引用指向Point对象并打印特征,然后将横纵坐标修改为 3和5后再次打印public class Point{ int x; int y; public static void main(String[] args){ Point point=new Point(); System.out.println("point的x值为:"+point.x); System.out.println("point的y值为:"+point.y); System.out.println("---------------------------------------"); point.x=3; point.y=5; System.out.println("point的x值为:"+point.x); System.out.println("point的y值为:"+point.y); } }
成员方法的定义• class 类名 {
返回值类型 成员方法名(形参列表) {
成员方法体;
}
}
• 当成员方法名由多个单词组成时,要求从第二个单词起每个单词的首字母大写。
class Person { void show() { System.out.println("没事秀一下!"); } }
返回值类型的详解
• 返回值主要指从方法体内返回到方法体外的数据内容。
• 返回值类型主要指返回值的数据类型,可以是基本数据类型,也可以是 引用数据类型。
• 当返回的数据内容是66时,则返回值类型写 int 即可
• 在方法体中使用return关键字可以返回具体的数据内容并结束当前方法。
• 当返回的数据内容是66时,则方法体中写 return 66; 即可
• 当该方法不需要返回任何数据内容时,则返回值类型写void即可。
形参列表的详解• 形式参数主要用于将方法体外的数据内容带入到方法体内部。
• 形式参数列表主要指多个形式参数组成的列表,语法格式如下:
数据类型 形参变量名1, 数据类型 形参变量名2, ...
• 当带入的数据内容是"hello"时,则形参列表写 String s 即可
• 当带入的数据内容是66和"hello"时,则形参列表写 int i, String s 即可
• 若该方法不需要带入任何数据内容时,则形参列表位置啥也不写即可。
方法的调用• 引用变量名.成员方法名(实参列表); 例:p.show();
• 实际参数列表主要用于对形式参数列表进行初始化操作,因此参数的个数、类型以及顺序都要完全一致。
• 实际参数可以传递直接量、变量、表达式、方法的调用等。
可变长参数• 返回值类型 方法名(参数的类型... 参数名) 例:int get_max(int... number)
• 方法参数部分指定类型的参数个数是可以改变的,也就是0~n个 。
• 一个方法的形参列表中最多只能声明一个可变长形参,并且需要放到参数列表的末尾。相当于*args
方法的传参过程• int max(int ia, int ib) { … … … }
int a = 5; int b=6; int res = m.max(a,b);
1. 为main方法中的变量a、b、res分配空间并初始化。
2. 调用max方法,为max方法的形参变量ia、ib分配空间。
3. 将实参变量的数值赋值到形参变量的内存空间中。
4. max方法运行完毕后返回,形参变量空间释放。
5. main方法中的res变量得到max方法的返回值。
6. main方法结束后释放相关变量的内存空间。
参数传递的注意事项• 基本数据类型的变量作为方法的参数传递时,形参变量数值的改变通常不会影响到实参变量的数值,因为两个变量有各自独立的内存空间;
• 引用数据类型的变量作为方法的参数传递时,形参变量指向内容的改变会影响到实参变量指向内容的数值,因为两个变量指向同一块内存空间,(当传递数组的时候,如果在方法体中改变了形参的内容,实参也会改变,但要是将形参的指向改变就不会影响到实参)
• 当引用数据类型的变量作为方法的参数传递时,若形参变量改变指向后再改变指定的内容,则通常不会影响到实参变量指向内容的改变,因为两个变量指向不同的内存空间。
内存结构之栈区• 栈用于存放程序运行过程当中所有的局部变量。一个运行的Java程序从开始到结束会有多次方法的调用。
• JVM会为每一个方法的调用在栈中分配一个对应的空间,这个空间称为该方法的栈帧。一个栈帧对应一个正在调用中的方法,栈帧中存储了该方法的参数、局部变量等数据。
• 当某一个方法调用完成后,其对应的栈帧将被清除
传参的相关概念• 参数分为形参和实参,定义方法时的参数叫形参,调用方法时传递的参数叫实参。
• 调用方法时采用值传递把实参传递给形参,方法内部其实是在使用形参。
• 所谓值传递就是当参数是基本类型时,传递参数的值,比如传递i=10,真实传参时,把10赋值给了形参。当参数是对象时,传递的是对象的值, 也就是把对象的地址赋值给形参。
构造方法的基本概念
class 类名 {
类名(形参列表) {
构造方法体;
}
}
• 构造方法名与类名完全相同并且没有返回值类型,连void都不许有。
• 在构造方法的第一行可以使用this()的方式来调用本类中的其它构造方法(了解)。
class Person { Person() { - Person类中的构造方法 } }
默认构造方法• 当一个类中没有定义任何构造方法时,编译器会自动添加一个无参空构造构造方法,叫做默认/缺省构造方法,如:Person(){}
• 若类中出现了构造方法,则编译器不再提供任何形式的构造方法。
构造方法的作用• 使用new关键字创建对象时会自动调用构造方法实现成员变量初始化工作。
案例题目• 编程实现Point类的定义并向Point类添加构造方法
Point() 默认创建原点对象
Point(int i, int j) 根据参数创建点对象
public class Point{ int x; int y; Point(int i,int j){ x=i; y=j; } Point(){} public static void main(String[] args){ Point point=new Point(); System.out.println("point的x值为:"+point.x); System.out.println("point的y值为:"+point.y); System.out.println("---------------------------------------"); Point point2=new Point(3,5); System.out.println("point的x值为:"+point2.x); System.out.println("point的y值为:"+point2.y); } }
方法重载的概念• 若方法名称相同,参数列表不同,这样的方法之间构成重载关系 (Overload)。
重载的体现形式• 方法重载的主要形式体现在:参数的个数不同、参数的类型不同、参数的顺序不同,与返回值类型和形参变量名无关,但建议返回值类型最好相同。
• 判断方法能否构成重载的核心:调用方法时能否加以区分。
练习题目• 编程实现为Point类添加重载的成员方法:
up() – 实现纵坐标减1的功能。
up(int dy) – 实现纵坐标减去参数指定数值的功能。
public class Point{ int x; int y; Point(int i,int j){ x=i; y=j; } Point(){} void up(){ y--; } void up(int dy){ y-=dy; } public static void main(String[] args){ Point point=new Point(); System.out.println("point的x值为:"+point.x); System.out.println("point的y值为:"+point.y); System.out.println("---------------------------------------"); Point point2=new Point(3,5); System.out.println("point2的x值为:"+point2.x); System.out.println("point2的y值为:"+point2.y); point2.up(); System.out.println("point2的y值为:"+point2.y); point2.up(7); System.out.println("point2的y值为:"+point2.y); } }
重载的实际意义• 方法重载的实际意义在于调用者只需要记住一个方法名就可以调用各种 不同的版本,来实现各种不同的功能。
• 如:java.io.PrintStream类中的println方法。
this的基本概念( 相当于python中的self,在调用成员变量的时候尽量使用self,增加可读性 )• 若在构造方法中出现了this关键字,则代表当前正在构造的对象。
• 若在成员方法中出现了this关键字,则代表当前正在调用的对象。
• this关键字本质上就是当前类类型的引用变量。
工作原理• 在构造方法中和成员方法中访问成员变量时,编译器会加上this.的前缀, 而this.相当于汉语中"我的",当不同的对象调用同一个方法时,由于调用 方法的对象不同导致this关键字不同,从而this.方式访问的结果也就随之 不同。
使用方式• 当局部变量名与成员变量名相同时,在方法体中会优先使用局部变量(就近原则),若希望使用成员变量,则需要在成员变量的前面加上this.的前 缀,明确要求该变量是成员变量(重中之重)。
• this关键字除了可以通过this.的方式调用成员变量和成员方法外,还可以 作为方法的返回值(重点)。
• 在构造方法的第一行可以使用this()的方式来调用本类中的其它构造方法(了解)。
注意事项• 引用类型变量用于存放对象的地址,可以给引用类型赋值为null,表示不指向任何对象。
• 当某个引用类型变量为null时无法对对象实施访问(因为它没有指向任何对象)。此时,如果通过引用访问成员变量或调用方法,会产生 NullPointerException 异常。
递归的基本概念• 递归本质就是指在方法体的内部直接或间接调用当前方法自身的形式。
注意事项• 使用递归必须有递归的规律以及退出条件。
• 使用递归必须使得问题简单化而不是复杂化。
• 若递归影响到程序的执行性能,则使用递推取代之。
案例题目• 编程实现参数n的阶乘并返回,所谓阶乘就是从1累乘到n的结果。
public class Mode2{ int jiecheng(int n){ if (n<1){ return 1; }else{ return n*this.jiecheng(n-1); } } public static void main(String[] args){ Mode2 temp=new Mode2(); int a=temp.jiecheng(5); System.out.print(a); } }
案例题目• 编程实现费式数列中第n项的数值并返回。
• 费式数列: 1 1 2 3 5 8 13 21 ……
public class Mode2{ int feishi(int n){ if (1==n ||2==n){ return 1; } return feishi(n-1)+feishi(n-2); } public static void main(String[] args){ Mode2 temp=new Mode2(); int a=temp.feishi(5); System.out.print(a); } }
封装的概念• 通常情况下可以在测试类给成员变量赋值一些合法但不合理的数值,无论是编译阶段还是运行阶段都不会报错或者给出提示,此时与现实生活不符。
• 为了避免上述错误的发生,就需要对成员变量进行密封包装处理,来隐藏成员变量的细节以及保证成员变量数值的合理性,该机制就叫做封装。
封装的实现流程• 私有化成员变量,使用private关键字修饰。
• 提供公有的get和set方法,并在方法体中进行合理值的判断。
• 在构造方法中调用set方法进行合理值的判断。
案例题目• 提示用户输入班级的学生人数以及每个学生的信息,学生的信息有:学号、姓名,最后分别打印出来。
• 提示:Student[] arr = new Student[num];
/*Student.java*/ public class Student{ private String name; private int id; public Student(){} public Student(int id,String name){ this.setId(id); this.setName(name); } public void setId(int id){ if(id>0){ this.id=id; }else{ System.out.println("id需要大于零的值"); } } public void setName(String name){ this.name=name; } public int getId(){ return id; } public String getName(){ return name; } public void show(){ System.out.println("id:"+this.getId()+" name:"+this.getName()); } }
/*StudentTest.java*/ import java.util.Scanner; public class StudentTest{ public static void main(String[] args){ System.out.println("请输入学生的人数"); Scanner sc=new Scanner(System.in); int num=sc.nextInt(); Student[] students=new Student[num]; for(int i=0;i
JavaBean的概念(了解)• JavaBean是一种Java语言写成的可重用组件,其它Java 类可以通过反射机 制发现和操作这些JavaBean 的属性。
• JavaBean本质上就是符合以下标准的Java类:
类是公共的
有一个无参的公共的构造器
有属性,且有对应的get、set方法
基本概念• 使用static关键字修饰成员变量表示静态的含义,此时成员变量由对象层级提升为类层级,也就是整个类只有一份并被所有对象共享,该成员变量随着类的加载准备就绪,与是否创建对象无关。
• static关键字修饰的成员可以使用引用.的方式访问,但推荐类名.的方式。
使用方式• 在非静态成员方法中既能访问非静态的成员又能访问静态的成员。
(成员:成员变量 + 成员方法, 静态成员被所有对象共享)
• 在静态成员方法中只能访问静态成员不能访问非静态成员。
(成员:成员变量 + 成员方法, 因为此时可能还没有创建对象)
• 在以后的开发中只有隶属于类层级并被所有对象共享的内容才可以使用static关键字修饰。(不能滥用static关键字)
构造块和静态代码块(熟悉)• 构造块:在类体中直接使用{}括起来的代码块。
(每创建一个对象都会执行一次构造块。)
• 静态代码块:使用static关键字修饰的构造块。
(静态代码块随着类加载时执行一次。所以静态代码块比构造快先执行)
public class SingletonTest { { System.out.println("代码块"); } static { System.out.println("静态代码块"); } public SingletonTest(){ System.out.println("构造方法"); } public static void main(String[] args) { SingletonTest slt=new SingletonTest(); } } /* 输出: 静态代码块 代码块 构造方法 */
又见main方法• 语法格式:
public static void main(String[] args){}
• 参数使用的举例。
//在dos运行类的时候: java 类名 参数1 参数2 参数3
案例题目(重中之重)• 编程实现Singleton类的封装。
• 编程实现SingletonTest类对Singleton类进行测试,要求main方法中能得 到且只能得到该类的一个对象。
public class Singleton { private int age; private String name; private static Singleton sc=new Singleton(); private Singleton(){ setAge(1); setName("bigload"); } public int getAge() { return age; } public String getName() { return name; } public void setAge(int age) { if (age>0){ this.age = age; }else { System.out.println("年龄不能为负数"); } } public void setName(String name) { this.name = name; } public void show(){ System.out.println(getName()+"的年龄是"+getAge()); } public static Singleton getSingleton(){ return sc; } }
package com.lagou.bigload.javaeasy; public class SingletonTest { public static void main(String[] args) { Singleton sc1=Singleton.getSingleton(); Singleton sc2=Singleton.getSingleton(); sc1.show(); sc2.show(); sc1.setAge(12); sc1.show(); sc2.show(); System.out.println("sc1:"+sc1); System.out.println("sc2:"+sc2); } } /* 输出: bigload的年龄是1 bigload的年龄是1 bigload的年龄是12 bigload的年龄是12 sc1:com.lagou.bigload.javaeasy.Singleton@246ae04d sc2:com.lagou.bigload.javaeasy.Singleton@246ae04d */
单例设计模式的概念
• 在某些特殊场合中,一个类对外提供且只提供一个对象时,这样的类叫做单例类,而设计单例的流程和思想叫做单例设计模式。
单例设计模式的实现流程• 私有化构造方法,使用private关键字修饰。
• 声明本类类型的引用指向本类类型的对象,并使用private static关键字共同修饰。
• 提供公有的get方法负责将对象返回出去,并使用public static关键字共同
修饰。
单例设计模式的实现方式• 单例设计模式的实现方式有两种:饿汉式 和 懒汉式,在以后的开发中推荐饿汉式。
饿汉式:上来就创建实例;懒汉式:有需要再创建实例;
public class Singleton { // 2.声明本类类型的引用指向本类类型的对象,使用private static关键字共同修饰 //private static Singleton sin = new Singleton(); // 饿汉式 private static Singleton sin = null; // 懒汉式 // 1.私有化构造方法,使用private关键字修饰 private Singleton() {} // 3.提供公有的get方法负责将对象返回出去,使用public static关键字共同修饰 public static Singleton getInstance() { //return sin; if(null == sin) { sin = new Singleton(); } return sin; } }
继承的由来继承的概念• 当多个类之间有相同的特征和行为时,可以将相同的内容提取出来组成一个公共类,让多个类吸收公共类中已有特征和行为而在多个类型只需要编写自己独有特征和行为的机制,叫做继承。
继承的概念• 在Java语言中使用extends(扩展)关键字来表示继承关系。
• 如:
public class Worker extends Person{} - 表示Worker类继承自Person类
其中Person类叫做超类、父类、基类。
其中Worker类叫做派生类、子类、孩子类。
• 使用继承提高了代码的复用性,可维护性及扩展性,是多态的前提条件。
继承的特点• 子类不能继承父类的构造方法和私有方法,但私有成员变量可以被继承只是不能直接访问。
• 无论使用何种方式构造子类的对象时都会自动调用父类的无参构造方法,来初始化从父类中继承的成员变量,相当于在构造方法的第一行增加代码super()的效果。
• 使用继承必须满足逻辑关系:子类 is a 父类,也就是不能滥用继承。
• Java语言中只支持单继承不支持多继承,也就是说一个子类只能有一个父类,但一个父类可以有多个子类。
方法重写的概念• 从父类中继承下来的方法不满足子类的需求时,就需要在子类中重新写一个和父类一样的方法来覆盖从父类中继承下来的版本,该方式就叫做方法的重写(Override)。
方法重写的原则• 要求方法名相同、参数列表相同以及返回值类型相同,从Java5开始允许返回子类类型。(即父类的方法会的的是父类的类型,则子类重写该方法时可以返回父类类型或是子类类型)
• 要求方法的访问权限不能变小,可以相同或者变大。
• 要求方法不能抛出更大的异常(异常机制)
案例题目
• 编程实现Animal类的封装,特征有:名字和毛色,要求提供打印所有特征的方法。
• 编程实现Dog类的封装并继承自Animal类,该类的特征有:牙齿数量,要求提供打印所有特征的方法。
• 编程实现DogTest类,在main方法中分别使用无参和有参方式构造Dog类型对象并打印特征。
public class Animal { private String name; private String color; public Animal(){} public Animal(String name,String color){ setName(name); setColor(color); } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getColor() { return color; } public void setColor(String color) { this.color = color; } public void show(){ System.out.println(getName()+"的颜色是"+getColor()); } }
public class Dog extends Animal { private int ya; public Dog(){} public Dog(String name,String color,int ya){ super(name,color); setYa(ya); } public int getYa() { return ya; } public void setYa(int ya) { if (ya>=0){ this.ya = ya; }else { System.out.println("不能小于零"); } } @Override public void show(){ super.show(); System.out.println(getName()+"的牙齿数是"+getYa()); } }
public class DogTest { public static void main(String[] args) { Dog dog1=new Dog(); Dog dog2=new Dog("旺财","白色",36); dog1.show(); dog2.show(); } }
又见构造块与静态代码块( 笔试 )• 先执行父类的静态代码块,再执行子类的静态代码块。
• 执行父类的构造块,执行父类的构造方法体。
• 执行子类的构造块,执行子类的构造方法体。
注意事项• public修饰的成员可以在任意位置使用。
• private修饰的成员只能在本类内部使用。
• 通常情况下,成员方法都使用public关键字修饰,成员变量都使用private关键字修饰。
package语句的由来• 定义类时需要指定类的名称,但如果仅仅将类名作为类的唯一标识,则不可避免的出现命名冲突的问题。这会给组件复用以及团队间的合作造成很大的麻烦!
• 在Java语言中,用包(package)的概念来解决命名冲突的问题。
包的定义• 在定义一个类时,除了定义类的名称一般还要指定一个包名,格式如下:
package 包名;
package 包名1.包名2.包名3...包名n;
• 为了实现项目管理、解决命名冲突以及权限控制的效果。
定义包的规范• 如果各个公司或开发组织的程序员都随心所欲的命名包名的话,仍然不能从根本上解决命名冲突的问题。因此,在指定包名的时候应该按照一定的规范。
• org.apache.commons.lang.StringUtil
• 其中StringUtils是类名而org.apache.commons.lang是多层包名,其含义如下:org.apache表示公司或组织的信息(是这个公司(或组织)域名的反写);common 表示项目的名称信息;lang 表示模块的名称信息。
包的导入• 使用import关键字导入包。
• 使用import关键字导入静态成员,从Java5.0开始支持。
例:import System.out ;之后就可以直接使用out.print();
基本概念• final本意为"最终的、不可改变的",可以修饰类、成员方法以及成员变量。
使用方式• final关键字修饰类体现在该类不能被继承。
- 主要用于防止滥用继承,如:java.lang.String类等。
• final关键字修饰成员方法体现在该方法不能被重写但可以被继承。
- 主要用于防止不经意间造成重写,如:java.text.Dateformat类中format方法等。
• final关键字修饰成员变量体现在该变量必须初始化且不能改变。
- 主要用于防止不经意间造成改变,如:java.lang.Thread类中MAX_PRIORITY等。
常量的概念• 在以后的开发中很少单独使用final关键字来修饰成员变量,通常使用 public static final关键字共同修饰成员变量来表达常量的含义,常量的命名规范要求是所有字母都要大写,不同的单词之间采用下划线连。
• public static final double PI = 3.14;
多态的概念• 多态主要指同一种事物表现出来的多种形态。
• 饮料:可乐、雪碧、红牛、脉动、...
• 宠物:猫、狗、鸟、小强、鱼、...
• 人:学生、教师、工人、保安、...
• 图形:矩形、圆形、梯形、三角形、…
多态的语法格式• 父类类型 引用变量名 = new 子类类型();
• 如:
Shape sr = new Rect();
sr.show();
案例题目
• 编程实现Shape类的封装,特征有:横纵坐标,要求提供打印所有特征的方法。
• 编程实现Rect类的封装并继承自Shape类,特征有:长度和宽度。
• 编程实现ShapeRectTest类,在main方法中分别创建Shape和Rect类型对象并打印特征。
public class Shape { private int x; private int y; public Shape(int x, int y) { this.x = x; this.y = y; } public static void test(){ System.out.println("我是父类的静态方法"); } public Shape() { } public int getX() { return x; } public void setX(int x) { this.x = x; } public int getY() { return y; } public void setY(int y) { this.y = y; } public void show(){ System.out.println("x轴为:"+getX()+" y轴为:"+getY()); } }
package com.lagou.bigload.javaeasy; public class Rect extends Shape{ private int h; private int w; public Rect(int x, int y, int h, int w) { super(x, y); this.h = h; this.w = w; } public Rect() { } public Rect(int h, int w) { this.h = h; this.w = w; } public int getH() { return h; } public void setH(int h) { this.h = h; } public int getW() { return w; } public void setW(int w) { this.w = w; } @Override public void show() { super.show(); System.out.println("w的值为:"+w+" h的值为:"+h); } public static void test(){ System.out.println("我是子类的静态方法"); } }
package com.lagou.bigload.javaeasy; public class ShapeRectTest { public static void main(String[] args) { Shape shape=new Shape(3,4); Shape rect=new Rect(3,6,3,8); shape.show(); rect.show(); rect.test(); } } /* 输出: x轴为:3 y轴为:4 x轴为:3 y轴为:6 w的值为:8 h的值为:3 我是父类的静态方法 */
多态的特点
• 当父类类型的引用指向子类类型的对象时,父类类型的引用可以直接调用父类独有的方法。
• 当父类类型的引用指向子类类型的对象时,父类类型的引用不可以直接调用子类独有的方法。
• 对于父子类都有的非静态方法来说,编译阶段调用父类版本,运行阶段调用子类重写的版本(动态绑定)。
• 对于父子类都有的静态方法来说,编译和运行阶段都调用父类版本。
引用数据类型之间的转换• 引用数据类型之间的转换方式有两种:自动类型转换 和 强制类型转换。
• 自动类型转换主要指小类型向大类型的转换,也就是子类转为父类,也叫做向上转型。
• 强制类型转换主要指大类型向小类型的转换,也就是父类转为子类,也叫做向下转型或显式类型转换。例:(Rect)shape
• 引用数据类型之间的转换必须发生在父子类之间,否则编译报错。
• 若强转的目标类型并不是该引用真正指向的数据类型时则编译通过,运行阶段发生类型转换异常。
• 为了避免上述错误的发生,应该在强转之前进行判断,格式如下:
if(引用变量 instanceof 数据类型)
判断引用变量指向的对象是否为后面的数据类型
多态的实际意义• 多态的实际意义在于屏蔽不同子类的差异性实现通用的编程带来不同的效果。
抽象方法的概念
• 抽象方法主要指不能具体实现的方法并且使用abstract关键字修饰,也就是没有方法体。
• 具体格式如下:
访问权限 abstract 返回值类型 方法名(形参列表);
public abstract void cry();
抽象类的概念• 抽象类主要指不能具体实例化的类并且使用abstract关键字修饰,也就是不能创建对象。
抽象类和抽象方法的关系• 抽象类中可以有成员变量、构造方法、成员方法;
• 抽象类中可以没有抽象方法,也可以有抽象方法;
• 拥有抽象方法的类必须是抽象类,因此真正意义上的抽象类应该是具有抽象方法并且使用abstract关键字修饰的类。
抽象类的实际意义• 抽象类的实际意义不在于创建对象而在于被继承。
• 当一个类继承抽象类后必须重写抽象方法,否则该类也变成抽象类,也就是抽象类对子类具有强制性和规范性,因此叫做模板设计模式。
开发经验分享• 在以后的开发中推荐使用多态的格式,此时父类类型引用直接调用的所有方法一定是父类中拥有的方法,若以后更换子类时,只需要将new关键字后面的子类类型修改而其它地方无需改变就可以立即生效,从而提高了代码的可维护性和可扩展型。
• 该方式的缺点就是:父类引用不能直接调用子类独有的方法,若调用则需要强制类型转换。
抽象类的应用• 银行有 定期账户和活期账户。继承自 账户类。账户类中:
public abstract class yinhang{ private double money; public abstract double getLixi(); public double getMoney() { return money; } } public class Account extends yinhang{ @Override public double getLixi(){ return getMoney()*0.2; } }
接口的基本概念• 接口就是一种比抽象类还抽象的类,体现在所有方法都为抽象方法。
• 定义类的关键字是class,而定义接口的关键字是interface。
• 如: 金属接口 货币接口 黄金类
练习题目• 编程实现Runner接口,提供一个描述奔跑行为的抽象方法。
• 编程实现Hunter接口继承Runner接口,并提供一个描述捕猎行为的抽象方法。
• 编程实现Man类实现Hunter接口并重写抽象方法,在main方法中使用多态方式测试。
//Runner.java public interface Runner { public abstract void running(); public static void cry(){ System.out.println("我嗷的一声,哭出了声"); } private void zz(){ System.out.println("眼睛一闭一睁就过去了"); } public default void yy(){ System.out.println("莫得怕"); zz(); } } //Hunter.java public interface Hunter extends Runner { public abstract void throwl(); } //Man.java public class Man implements Hunter { @Override public void throwl() { System.out.println("如果你抓到我,我就让你嘿嘿嘿"); } @Override public void running() { System.out.println("你来追我呀"); } public static void main(String[] args) { Man man=new Man(); man.running(); man.throwl(); Runner.cry(); man.yy(); } } /* * 输出: 你来追我呀 如果你抓到我,我就让你嘿嘿嘿 我嗷的一声,哭出了声 莫得怕 眼睛一闭一睁就过去了 * */
抽象类和接口的主要区别(笔试题)• 定义抽象类的关键字是abstract class,而定义接口的关键字是interface。
• 继承抽象类的关键字是extends,而实现接口的关键字是implements。
• 继承抽象类支持单继承,而实现接口支持多实现。
• 抽象类中可以有构造方法,而接口中不可以有构造方法。
• 抽象类中可以有成员变量,而接口中只可以有常量。
抽象类和接口的主要区别• 抽象类中可以有成员方法,而接口中只可以有抽象方法。
• 抽象类中增加方法时子类可以不用重写,而接口中增加方法时实现类需要重写(Java8以前的版本)。
• 从Java8开始增加新特性,接口中允许出现非抽象方法和静态方法,但非抽象方法需要使用default关键字修饰。(静态方法使用接口名.方法名()使用)
• 从Java9开始增加新特性,接口中允许出现私有方法。
内部类的基本概念• 当一个类的定义出现在另外一个类的类体中时,那么这个类叫做内部类 (Inner),而这个内部类所在的类叫做外部类(Outer)。
• 类中的内容:成员变量、成员方法、构造方法、静态成员、构造块和静态代码块、内部类。
实际作用• 当一个类存在的价值仅仅是为某一个类单独服务时,那么就可以将这个类定义为所服务类中的内部类,这样可以隐藏该类的实现细节并且可以方便的访问外部类的私有成员而不再需要提供公有的get和set方法。
内部类的分类• 普通内部类 - 直接将一个类的定义放在另外一个类的类体中。
• 静态内部类 - 使用static关键字修饰的内部类,隶属于类层级。
• 局部内部类 - 直接将一个类的定义放在方法体的内部时。
• 匿名内部类 - 就是指没有名字的内部类。
普通(成员)内部类的格式• 访问修饰符 class 外部类的类名 {
访问修饰符 class 内部类的类名 {
内部类的类体;
}
}
普通内部类的使用方式• 普通内部类和普通类一样可以定义成员变量、成员方法以及构造方法等。
• 普通内部类和普通类一样可以使用final或者abstract关键字修饰。
• 普通内部类还可以使用private或protected关键字进行修饰。
• 普通内部类需要使用外部类对象来创建对象。
• 如果内部类访问外部类中与本类内部同名的成员变量或方法时,需要使用this关键字。
静态内部类的格式• 访问修饰符 class 外部类的类名 {
访问修饰符 static class 内部类的类名 {
内部类的类体;
}
}
静态内部类的使用方式• 静态内部类不能直接访问外部类的非静态成员。
• 静态内部类可以直接创建对象。(普通内部类需要实例化类对象在实例化内部类对象)
• 如果静态内部类访问外部类中与本类内同名的成员变量或方法时,需要使用类名.的方式访问。
局部(方法)内部类的格式• 访问修饰符 class 外部类的类名 {
访问修饰符 返回值类型 成员方法名(形参列表) {
class 内部类的类名 {
内部类的类体;
}
}
}
局部内部类的使用方式• 局部内部类只能在该方法的内部可以使用。
• 局部内部类可以在方法体内部直接创建对象。
• 局部内部类不能使用访问控制符和static关键字修饰符。
• 局部内部类可以使用外部方法的局部变量,但是必须是final的。由局部内部类和局部变量的声明周期不同所致。
回调模式的概念• 回调模式是指——如果一个方法的参数是接口类型,则在调用该方法时, 需要创建并传递一个实现此接口类型的对象;而该方法在运行时会调用到参数对象中所实现的方法(接口中定义的)。
开发经验分享• 当接口/类类型的引用作为方法的形参时,实参的传递方式有两种:
• 自定义类实现接口/继承类并重写方法,然后创建该类对象作为实参传递;
• 使用上述匿名内部类的语法格式得到接口/类类型的引用即可;
匿名内部类的语法格式(重点)• 接口/父类类型 引用变量名 = new 接口/父类类型() { 方法的重写 };
枚举的基本概念• 一年中的所有季节:春季、夏季、秋季、冬季。
• 所有的性别:男、女。
• 键盘上的所有方向按键:向上、向下、向左、向右。
• 在日常生活中这些事物的取值只有明确的几个固定值,此时描述这些事物的所有值都可以一一列举出来,而这个列举出来的类型就叫做枚举类型。
枚举的定义• 使用public static final表示的常量描述较为繁琐,使用enum关键字来定
义枚举类型取代常量,枚举类型是从Java5开始增加的一种引用数据类型。
• 枚举值就是当前类的类型,也就是指向本类的对象,默认使用public static final关键字共同修饰,因此采用枚举类型.的方式调用。
• 枚举类可以自定义构造方法,但是构造方法的修饰符必须是private,默 认也是私有的。
public enum cardType { BIG("大卡"),SMALL("小卡"),LITTLE("微型卡"); private final String card; // 用于描述方向字符串的成员变量 // 通过构造方法实现成员变量的初始化,更加灵活 // 1.私有化构造方法,此时该构造方法只能在本类的内部使用 private cardType(String card) { this.card = card; } // 通过公有的get方法可以在本类的外部访问该类成员变量的数值 public String getCard() { return card; } }
枚举类实现接口的方式• 枚举类实现接口后需要重写抽象方法,而重写方法的方式有两种:重写一个,或者每个对象都重写。
public enum cardType implements internetService { BIG("大卡"){ @Override public void showInternet(int internetNumber, PhoneCard phone) { } },SMALL("小卡"){ @Override public void showInternet(int internetNumber, PhoneCard phone) { } },LITTLE("微型卡"){ @Override public void showInternet(int internetNumber, PhoneCard phone) { } }; private final String card; // 用于描述方向字符串的成员变量 // 通过构造方法实现成员变量的初始化,更加灵活 // 1.私有化构造方法,此时该构造方法只能在本类的内部使用 private cardType(String card) { this.card = card; } // 通过公有的get方法可以在本类的外部访问该类成员变量的数值 public String getCard() { return card; } }
注解的基本概念• 注解(Annotation)又叫标注,是从Java5开始增加的一种引用数据类型。
• 注解本质上就是代码中的特殊标记,通过这些标记可以在编译、类加载、以及运行时执行指定的处理。
注解的语法格式• 访问修饰符 @interface 注解名称 {
注解成员;
}
• 自定义注解自动继承java.lang.annotation.Annotation接口。
• 通过@注解名称的方式可以修饰包、类、 成员方法、成员变量、构造方法、参数、局部变量的声明等。
注解的使用方式
• 注解体中只有成员变量没有成员方法,而注解的成员变量以“无形参的方法”形式来声明,其方法名定义了该成员变量的名字,其返回值定义了该成员变量的类型。
• 如果注解只有一个参数成员,建议使用参数名为value,而类型只能是八种基本数据类型、String类型、Class类型、enum类型及Annotation类型。
元注解的概念• 元注解是可以注解到注解上的注解,或者说元注解是一种基本注解,但是它能够应用到其它的注解上面。
• 元注解主要有 @Retention、@Documented、@Target、@Inherited、@Repeatable。
元注解@Retention• @Retention 应用到一个注解上用于说明该注解的的生命周期,取值如下:
• RetentionPolicy.SOURCE 注解只在源码阶段保留,在编译器进行编译时它将被丢弃忽视。
• RetentionPolicy.CLASS 注解只被保留到编译进行的时候,它并不会被加载到 JVM 中,默认方式。
• RetentionPolicy.RUNTIME 注解可以保留到程序运行的时候,它会被加载进入到 JVM 中,所以在程序运行时可以获取到它们。
元注解@Inherited• @Inherited并不是说注解本身可以继承,而是说如果一个超类被该注解标记过的注解进行注解时,如果子类没有被任何注解应用时,则子类就继承超类的注解。
1. 编程实现以下需求:
定义一个长度为[16][16]的整型二维数组并输入所有位置的元素值,分别实现二维数组中所有行和所有列中所有元素的累加和并打印。
再分别实现二维数组中左上角到右下角和右上角到左下角所有元素的累加和并打印。
2. 编程实现控制台版并支持两人对战的五子棋游戏。
(1)绘制棋盘 - 写一个成员方法实现
(2)提示黑方和白方分别下棋并重新绘制棋盘 - 写一个成员方法实现。
(3)每当一方下棋后判断是否获胜 - 写一个成员方法实现。
(4)提示: 采用二维数组来模拟并描述棋盘,棋盘如下:
3. 按照要求设计并实现以下实体类和接口。
3.1 第一步:设计和实现以下类
(1)手机卡类 特征:卡类型、卡号、用户名、密码、账户余额、通话时长(分钟)、上网流量 行为:显示(卡号 + 用户名 + 当前余额)
(2)通话套餐类 特征:通话时长、短信条数、每月资费 行为: 显示所有套餐信息 (3)上网套餐类 特征:上网流量、每月资费 行为:显示所有套餐信息
(4)用户消费信息类 特征:统计通话时长、统计上网流量、每月消费金额
3.2 第二步:设计和实现以下枚举类 手机卡的类型总共有 3 种:大卡、小卡、微型卡
3.3 第三步:实体类的优化 将通话套餐类和上网套餐类中相同的特征和行为提取出来组成抽象套餐类。
3.4 第四步:创建并实现以下接口
(1)通话服务接口 抽象方法: 参数 1: 通话分钟, 参数 2: 手机卡类对象 让通话套餐类实现通话服务接口。
(2)上网服务接口 抽象方法: 参数 1: 上网流量, 参数 2: 手机卡类对象 让上网套餐类实现上网服务接口。
3.5 第五步:进行代码测试
编写测试类使用多态格式分别调用上述方法,方法体中打印一句话进行功能模拟即可。
因为这次作业太多了,所以分享出码云,只是我的做法,有什么不对的,还望指正!!!
https://gitee.com/bigload/java_big_data/tree/master/mode2