一.Java语言中的数据类型分为两大类,分别是基本类型和引用类型。
基本数据类型
Java基本类型共有八种,基本类型可以分为三类,字符类型char,布尔类型boolean以及数值类型byte、short、int、long、float、double。数值类型又可以分为整数类型byte、short、int、long和浮点数类型float、double。JAVA中的数值类型不存在无符号的,它们的取值范围是固定的,不会随着机器硬件环境或者操作系统的改变而改变。实际上,JAVA中还存在另外一种基本类型void,它也有对应的包装类 java.lang.Void,不过我们无法直接对它们进行操作。
整型(4个): byte(字节型)、short(短整型)、int(整型)、long(长整型)
byte a = 100;
short s = 1000;
int a = 100000;
long a = 100000L;
复制
注. 声明long类型数据的时候,后面需要加L或者l (一般加大写L);
浮点型(2个):float(单精度型/浮点型) 、double(双精度型)
float f1 = 1.1f;
double d1 = 1.2;
注:
声明float类型的数据的时候加f或者F;
double类型的数据的有效位数 15~16;
3.float类型的数据有效位数是 6~7;
字符(1个): char(字符型)
**注.**声明char类型的数据的时候,使用单引号声明。并且单引号里面只能放一个元素;
char name = 'a'
复制
布尔类型:(1个): boolean(布尔类型)
一般用来做逻辑判断,一般用于流程控制,数据值只有true或false,适用于逻辑计算。
二.java运算符有六类:算数运算符、赋值运算符、关系运算符、逻辑运算符、位运算符、三元运算符。
表达式是指:用运算符把常量或变量连接起来符合java语法的式子 。
1.算数运算符
注意事项:/ 运算符取的是商的值,比如int只能取到整数的值,要想取到小数位数要用double或者float, % 运算符取的是结果的余数
字符的“+”操作
char类型参与算术运算,使用的是计算机底层对应的十进制数值。需要我们记住三个字符对应的数值:
‘a’ – 97 a-z是连续的,所以’b’对应的数值是98,'c’是99,依次递加
‘A’ – 65 A-Z是连续的,所以’B’对应的数值是66,'C’是67,依次递加
‘0’ – 48 0-9是连续的,所以’1’对应的数值是49,'2’是50,依次递加
算术表达式中包含不同的基本数据类型的值的时候,整个算术表达式的类型会自动进行提升。
提升规则:
byte类型,short类型和char类型将被提升到int类型,不管是否有其他类型参与运算。
整个表达式的类型自动提升到与表达式中最高等级的操作数相同的类型
等级顺序:byte,short,char --> int --> long --> float --> double
2.赋值运算符
3.关系运算符
4.逻辑运算符
逻辑运算符把各个运算的关系表达式连接起来组成一个复杂的逻辑表达式,以判断程序中的表达式是否成立,判断 的结果是 true 或 false。
5.位运算符
Java定义了位运算符,应用于整数类型(int),长整型(long),短整型(short),字符型(char),和字节型(byte)等类型。位运算符作用在所有的位上,并且按位运算。
6、三元运算符
语法格式:
关系表达式 ? 表达式1 : 表达式2;
解释 :问号前面的位置是判断的条件,判断结果为boolean型,为true时调用表达式1,为false时调用表达式2。其逻辑为:如果条件表达式成立或者满足则执行表达式1,否则执行表达式2。
三.
程序控制语句
JAVA程序控制语句分为三类:选择,循环,跳转语句。
1.if语句
if语句是JAVA中的条件分支语句,将程序的执行路径分为两条。
if(判断条件)
{执行语句}
else
{执行语句}
if语句执行过程是:
如果条件为真,执行 if 后面的语句,如果为假执行 else 后面的语句。
2.switch语句
switch语句是JAVA中的多分支语句,它基于表达式的值使程序执行不同语句序列。
格式如下:
switch ()
{
case 目标值1:
执行语句1
break;
case 目标值2:
执行语句2
break;
...........
...........
case 目标值n:
执行语句n
break;
default:
执行语句 n+1
break;
}
注意:
break表示中断,结束switch语句。
default表示所有情况不匹配的时候,就执行该处的内容。
3.while语句
while语句是JAVA最基本的循环语句,当它的条件表达式是true时,while语句重复执行循环体。
格式如下:
while(循环条件)
{
执行语句
.......
}
4.do-while语句
do-while语句它的循环体至少先执行一次,因为它的条件表达式在循环的结尾。
格式:
do
{
执行语句
.......
}while(循环条件)
5.for语句
for循环执行过程:
1.初始化表达式确定初始条件
2.进入循环条件,判断初始化条件是否成立,如果成立,则执行{ }内的语句,不成立就结束。
3.然后执行操作表达式,将条件改变。
4.条件改变后,再执行循环条件,判断条件改变后是否成立,重复第二步,就这样依次循环,直到条件成立。
6.break语句
JAVA中break语句有三种作用:
第一:在switch语句中,它被用来终止一个语句块。
第二:它能被用来退出一个循环。
第三:break后面加语句标签实现跳转。
7.continue语句
有时需要强迫一次循环提前结束从而进入下一次循环。
8.return语句
return语句用来明确的从一个方法返回,使程序控制权返回到调用它的方法,因此return语句也属于跳转语句。
四.Java数组
1.数组的定义数组是相同类型数据的有序集合。数组描述的是相同类型的若干个数据,按照一定的先后次序排列组合而成。其中,每一个数据称作一个数组元素,每个数组元素可以通过一个下标来访问它们。
2.数组的声明与创建首先必须声明数组变量,才能在程序中使用数组。下面是声明数组变量的语法:``··dataType[] arrayRefVar;//首选的方法或dataType arrayRefVar[];//效果相同,但不是首选方法Java语言使用new操作符来创建数组,语法如下:dataType[ ] arrayRefVar = new dataType[ arraySize];数组的元素是通过索引访问的,数组索引从О开始。获取数组长度:arrays.length
3.数组的四个基本特点其长度是确定的。数组一旦被创建,它的大小就是不可以改变的。其元素必须是相同类型,不允许出现混合类型。数组中的元素可以是任何数据类型,包括基本类型和引用类型。数组变量属引用类型,数组也可以看成是对象,数组中的每个元素相当于该对象的成员变量。数组本身就是对象,Java中对象是在堆中的,因此数组无论保存原始类型还是其他对象类型,数组对象本身是在堆中的。
4.三中初始化及内存分析三种初始化静态初始化:int[] a = {1,2,3};Man[ ] mans = {new Man(1,1),new Man(2,2)};动态初始化:int[] a = new int[2];a[0]=1;a[1]=2;数组的默认初始化:数组是引用类型,它的元素相当于类的实例变量,因此数组一经分配空间,其中的每个元素也被按照实例变量同样的方式被隐式初始化。
5.下标越界及小结数组的四个基本特点其长度是确定的。数组一旦被创建,它的大小就是不可以改变的。其元素必须是相同类型,不允许出现混合类型。数组中的元素可以是任何数据类型,包括基本类型和引用类型。数组变量属引用类型,数组也可以看成是对象,数组中的每个元素相当于该对象的成员变量。数组本身就是对象,Java中对象是在堆中的,因此数组无论保存原始类型还是其他对象类型,数组对象本身是在堆中的。
6.数组边界下标的合法区间:[0, length-1],如果越界就会报错;
public static void main( String[] args) {int[] a=new int[2];
system.out.println(a[2]);}
ArraylndexOutOfBoundsException:数组下标越界异常!
小结:数组是相同数据类型(数据类型可以为任意类型)的有序集合。数组也是对象。数组元素相当于对象的成员变量数组长度的确定的,不可变的。如果越界,则报:ArraylndexOutofBounds
7. 数组的使用
普通For循环For-Each循环数组作方法入参数组作返回值
8.二维数组
多维数组:多维数组可以看成是数组的数组,比如二维数组就是一个特殊的一维数组,其每一个元素都是一个一维数组。二维数组 int a[][] = new int[2][5];以上二维数组a可以看成一个两行五列的数组。
9.Arrays类详解数组的工具类java.util.Arrays由于数组对象本身并没有什么方法可以供我们调用,但API中提供了一个工具类Arrays供我们使用,从而可以对数据对象进行一些基本的操作。
Arrays类中的方法都是static修饰的静态方法,在使用的时候可以直接使用类名进行调用,而"不用"使用对象来调用(注意:是"不用”而不是"不能")。具有以下常用功能:给数组赋值:通过fill方法。
对数组排序:通过sort方法,按升序。
比较数组:通过equals方法比较数组中元素值是否相等。
查找数组元素:通过binarySearch方法能对排序好的数组进行二分查找法操作。
10.冒泡排序冒泡排序是八大排序算法之一。
冒泡的代码还是相当简单的,两层循环,外层冒泡轮数,里层依次比较。
我们看到嵌套循环,应该立马就可以得出这个算法的时间复杂度为O(n2)
11.稀疏数组当一个数组中大部分元素为0,或者为同一值的数组时,可以使用稀疏数组来保存该数组。稀疏数组的处理方式是:记录数组一共有几行几列,有多少个不同值。把具有不同值的元素和行列及值记录在一个小规模的数组中,从而缩小程序的规模。
第三章 面向对象程序进阶(基础)
第三章 面向对象程序进阶(基础)
一、面向对象的基本概念
面向对象最关键的两个词汇是类和对象。面向对象就是:把数据及对数据的操作方法放在一起,作为一个相互依存的整体。类是具备某些共同特征的实体的集合,它是一种抽象的概念;类是一种抽象的数据类型,它是对具有相同特征的实体的抽象;类是一个模板,描述类的行为和状态。软件对象也有状态和行为,软件对象的状态就是属性,行为通过方法实现,在软件开发中,方法操作对象内部状态的改变,对象的相互调用也通过方法来完成。
面向对象中的主要内容包括类和对象的关系、类的定义、对象的创建、类的三大特征、抽象类和接口等。
二、类和对象
万物皆为对象,对象的实质是属性和行为。在我们的周围会有很多对象,例如人、书本都是对象。所谓对象就是真实世界中的实体,对象和实体都是一一对应的,也就是说现实世界中的每一个实体都是一个对象,它是一种具体的概念。
具有相同特性和行为的对象的抽象就是类,因此对象的抽象就是类,类的具体化就是对象。所以说类是实体对象的概念模型,因此通常是笼统的、不具体的。在软件开发中,方法操作对象内部状态的改变,对象的相互调用也通过方法来完成。
1.类是对象的抽象,它用于描述一组对象的共同特征和行为。类中可以定义成员变量和成员方法,其中成员变量用于描述对象的特征,也称作属性,成员方法用于描述对象的行为,可简称方法。
如何创建类:
class Person{
//定义int 类型的变量
int age;
//定义speak()方法
void speak (){
System.out.println(“***”)
}
} //Person 类名,age 是成员变量,speak()成员方法
2、对象的创建与使用:
创建:类名 对象名= new 类名();//实例对象
使用: 对象引用.对象成员;
实例化对象时,Java虚拟机会自动为成员变量进行初始化,针对不同类型的成员变量,赋予不同的初始值。
成员变量类 初始值 成员变量类 初始值
byte 0 double 0.0D
short 0 char 空字符,'\u0000'
int 0 boolean false
long 0L 引用数据类型 null
float 0.0F
在Java中,null是一种特殊的常量,当一个变量的值为null时,则表示该变量不指向任何一个对象,变成垃圾被回收。
3、所谓的类的封装是指定义一个类时,将类中的属性私有化,即利用private 关键字来修饰,私有属性只能在它所在类中被访问。为了能让外界访问私有属性,需要提供一些使用public 修饰的公用方法,其中包括用于获得属性值得getXXX()方法和设置属性值得setXXX()方法。
构造方法
2、构造方法:构造方法是类中一个特殊成员,它会在实例化对象时被自动调用。
构造方法的特点:
①方法名与类名相同;
②在方法名前面没有返回值类型的声明;
③在方法中不能使用return语句返回一个值;
class Person{
//构造方法
public Person(){
//无参构造方法
}
public Person(int age){
age = a; //有参构造方法
}
public void speak(){
System.out.println(“I am” +age+”years old !");
}
}
public class Example{
public static void main (String [] args){
Person p = new Person(20); //实例化Person对象
p.speak();
}
}
构造方法的重载:与普通方法一样,方法名相同,只需要参数类型或参数个数不同即可。
一般情况下,构造方法通常会使用public来修饰。
3、类的继承
类的继承是指在一个现有类的基础上去构建一个新的类,构建出来的新类被称作子类,现有类被称作父类,子类会自动拥有父类所有可继承的属性和方法,使用extends关键字。
class A{}
class B extends A{}
在Java中继承的体现:
①Java允许单继承。不直接支持多继承,将多继承进行其他方式的体现。
②单继承:一个子类只能有一个父类。
class A{}
class B{}
class C extends A,B{} //C类不可以同时继承A类和B类
③多继承:一个子类可以有多个父类,用多实现体现。
④多重继承,继承体系。
学习继承体系时,应该参阅顶层的类中的内容,了解这个体系的基本功能。使用这个体系功能,需要创建最子类的对象。(看顶层,建底层。)
override:子父类中的定义了一模一样的函数。运行的结果:子类的函数在运行。这种情况在子父类中,是函数的另一个特性:override(重写、覆盖、复写)。
重写的注意事项:
①子类覆盖父类,必须保证权限要大于或等于父类的权限。
②静态覆盖静态。
③写法上必须一模一样,函数的返回值类型 函数名 参数列表都要一样。
4、抽象类和接口
1、abstract(抽象)
抽象类:在描述事物时,没有足够的信息描述一个事物,这时该事物就是抽象事物。
定义了抽象函数的类,也必须被abstract关键字修饰,被abstract关键字修饰的类是抽象类。
抽象方法的类必须声明为抽象类,但抽象类可以不包含任何抽象方法,只要abstract关键字修饰即可。
【抽象类的特点】
①抽象类和抽象方法都需要被abstract修饰。(抽象方法一定要定义在抽象类中)。
//定义抽象类Animal
abstract class Animal{
//定义抽象方法shuot()
abstract int shout ();
}
②抽象类不可以创建实例,原因:调用抽象方法没有方法体。
③只要覆盖了抽象类中所有的抽象方法后,其子类才可以实例化。否则该子类还是一个抽象类。
之所以继承,更多的是在思想,是面对共性类型操作会更简单。
5、接口(interface)
接口:如果一个类中的所有抽象方法都是抽象的,则可以将这个类用另外一种方式来定义,即接口。在定义接口时,需要使用interface关键字来声明,如:
interface Animal{
int ID = 1; //定义全局变量
void breathe(); //定义抽象方法
void run ();
} // Animal 即为一个接口,接口中定义的的方法和变量都包含一些默认修饰符“public abstract”(抽象方法)“public static final”(全局变量)。
接口的特点:
①接口可以创建对象;
②子类必须覆盖掉接口中所有的抽象方法后,子类才可以实例化。否则子类是一个抽象类。
③实现多接口示例:
interface Run{
程序代码…..
}
interface Fly{
程序代码…..
}
class Bird implements Run,Fly{
程序代码…….
}
定义子类去覆盖接口的方法:子类必须和接口产生关系,类与类的关系是继承,类与接口之间的关系是实现,通过关键字implements 。
接口最重要的体现:解决多继承的弊端。将多继承这种机制在Java中通过多实现完成。
多继承的弊端:当多个父类中有相同功能时,子类调用会产生不确定性。
其核心原因就是在于多继承父类中功能有主体,而导致调用运行时,不确定运行哪个主体内容。
接口中的功能都没有方法体,由子类来明确。
如果子类想要继承扩展其他类中的功能,可通过接口实现:
class Dog extends Canidae implements Animal{ //先继承,再实现
程序代码……
}
父类定义事物的基本功能,接口定义事物的扩展功能。
接口出现后的一些细节:类与类之间是继承关系,类与接口是实现关系;接口与接口之间是继承关系,而且可以多继承。
6、多态
多态的概述
父类的引用或者接口的引用指向了自己的子类对象。
Dog d = new Dog(); // Dog对象的类型是Dog类型
Animal a = new Dog(); // Dog对象的类型右边是Dog类型,左边Animal 类型。
【好处】
提高了程序的扩展性。
【弊端】
通过父类引用操作子类对象时,只能使用父类中已有的方法,不能操作子类特有的方法。
【前提】
①必须有关系,继承、实现。
②通常都有重写操作。
三、成员变量及this、static关键词
根据定义变量位置的不同,可以将变量分成两大类:成员变量(存在于堆内存中,和类一起创建)和局部变量(存在于栈内存中)。二者的运行机制存在较大变异。
成员变量是定义在类中、方法体之外的变量。这种变量会在创建对象的时候自动初始化。
类的构造方法也称类的构造器,每个类中都默认存在一个,与类名完全相同,没有返回值类型修饰符(包括void),没有参数的方法。
构造方法也是类中的方法,支持方法的重载。构造方法的特点:(1)构造方法没有返回值。(2)构造方法的名称要与本类的名称相同。
Public Book(){
... //构造方法体
}
在构造方法中可以为成员变量赋值,这样当实例化一个本类对象时,相应的成员变量也将被初始化。如果类中没有明确定义构造方法,编译器会自动创建一个不带参数的默认构造方法。构造方法分为两总:无参构造方法和有参构造方法。
this关键字用于表示本类当前的对象,当前对象不是某个new出来的实体对象,而是当前正在编辑的类。
Public void setName(String name){ //定义一个setName()方法
this.name=name; //将参数值赋予类中的成员变量
}
在上述代码中可以看到,成员变量与setName()方法中的形式参数的名称相同,都为name,在java语言中规定使用this关键字来代表蓓蕾兑现的引用,this关键字被隐式地用于引用对象的成员变量和方法,如在上述代码中,this.name指的就是Book类中的name成员变量,而this.name=name语句中的第二个name则指的是形参name。实质上,setName()方法实现的功能就是将形参name的值赋予成员变量name。
其实,this除了可以调用成员变量和成员方法,还可以作为方法的返回值。例如,返回图书类本类的对象,可以写成以下这种形式:
public Book getBook(){
Return this; //返回Book类的本类对象
}
在getBook()方法中,返回值为Book类,所以方法体中使用return this这种形式返回Book类对象。
Static关键字主要用于内存管理。它主要在成员变量、成员方法、块和内部类中使用。static关键字属于类,但不是类的实例。它有三个作用:(1)修饰成员变量;(2)修饰成员方法;(3)静态块。
第四章
面向对象程序设计(进阶)
1.封装:
封装(Encapsulation)是面向对象方法的重要原则,就是把对象的属性和操作(或服务)结合为一个独立的整体,并尽可能隐藏对象的内部实现细节。”被封装的类通常称为抽象数据类型
通俗来说:当对象调用被封装的方法时,只能看到我想让你看到的。
1.1封装的作用:
保护我们的代码不会被我们无意间修改破坏
使得代码高内聚和低耦合
“高内聚和低耦合”:
高内聚:尽量操作内容都是自己内部完成的,使自己内部的内容联系紧密,一个类负责一个任务
方便后期修改。
低耦合:“仅需暴露少量的方法给外部使用,尽量方便外部使用。就是说简化外部调用,便有调用者使用,便于扩展和协作。
1.2如何封装:
类的封装就是将类的属性私有化,即用private进行修饰。私有属性只能在他类中被访问
如果外界想要访问私有属性,需要提供一些使用public修饰的公有方法。其中包括用于获取属性值的get方法和设置属性值的set方法 。
几种权限修饰符:
private:私有权限,只能在定义的类中访问,在其他类中创建的实例均无法访问
默认:同包可访问权限,在没有声明权限修饰符时为默认权限,允许在同包的其他类访问
protected:受保护权限,允许有继承关系的子类访问
public:公共权限,允许任何类访问
如何定义变量:
[权限修饰符] 变量类型 变量名
封装步骤:
新建类
属性名封装但是方法用public提供调用功能也就是建立get/set方法。
2.继承:
这是一个非常形象的概念,就像是日常生活中子女继承父辈的遗产。在程序中大致是这样的:
有两个类一个是动物还有一个类是猫,程序中可以描述为猫是继承(extends)自动物这个类的
那么这个动物类就可以称为猫的父类,猫就是动物的子类。
一个父类可以有多个子类但一个子类只能有一个父类就像一个人不能有多个亲爹一样,但一个父可以有多个孩子一样。
2.1继承性的作用:
多个类都有共同的属性,行为时,就可以向上抽取相同的属性行为,就不用在重新定义了。
所以可以说,父类是由子类向上抽取共性而来的。
总结:
1.继承类(子类)获得(父类)被继承类的方法和属性前提是,父类中方法属性非私有
2父类是由子类向上抽取共性而来的。
3.因为子类是继承是父类所以子类的功能要大于父类,不然继承没啥意义。
继承性的格式(extends):
public class 父类{
}
public class 子类 extends 父类{
}
3.super关键字
super不是引用类型
super中存储的不是内存地址,super指向的不是父类型对象
this中存储的是内存地址,指向当前对象
.super代表的是当前子类对象中的父类型特征
如果子类中没有定义name,那么在子类中name;this.name;super.name都是一样的,都指的是父类中的name。如果子类中重新定义了name,那么子类中的name;this.name指的是子类中的name,super.name才代表父类中的name
什么时候使用super?
子类和父类中都有某个数据,如果要在子类中访问父类中的属性,需要使用super
.super可以用在什么地方?
成员方法中
构造方法中
无法在静态方法中使用(this也不可以)
super关键字在构造方法中
语法:super(实参);
作用:代码重用;通过子类的构造方法去调用父类的构造方法(给当前子类中的父类型特征赋值)
语法规则:一个构造方法第一行如果没有this(…)也没有显示的去掉用super(…)系统会默认调用super()
super(…)的调用只能放在构造方法的第一行
this(…)也只能出现在构造方法的第一行,所以super和this不能共存
父类中的构造方法不会被子类继承,在子类中用super可以调用,super虽然调用了父类中的构造方法,但只会给当前子类中的父类型特征赋值,并不会创建父类对象
【注】在java中只要是创建对象,那么object类中的无参数构造方法一定会执行
单例模式的特点之一是构造方法私有化。子类中的super无法调用父类中的构造方法,会导致编译不通过。所以单例模式一个缺陷是没有子类,无法被继承。
4.final关键字
final:最终的
final可以用来修饰的结构:类,方法,属性
final用来修饰一个类:此类不可以被其他类所继承
例如:String类,System类,StringBuffer类
final用来修饰方法:此方法不可以被重写
比如Object类中的,getClass()方法
final用来修饰变量:此时"变量"就称为一个常量了。
5.1.final修饰属性:可以考虑赋值的位置有:显示初始化,代码块中初始化,使用构造器初始化。
5.2. final修饰局部变量:
尤其是使用final修饰形参时,表明此参数是一个常量,当我们调用此方法时,给这个常量形参赋一个实参,一旦赋值以后,就只能在方法体内使用此形参,但不能进行重新赋值。
package demo9;
public class FinalTest
{ int num; private void SetText(final int num)
{ // num=20; //编译不通过,不能给final 变量赋值 System.out.println(num); }
public static void main(String[] args) { FinalTest f1=new FinalTest(); f1.SetText(20); } }
final使用细节:
5.object
理解面向对象
面向对象是相对面向过程而言
面向过程
强调的是功能行为
面向对象
将功能封装进对象,强调具备了功能的对象。
面向对象的特点
是一种符合人们思考习惯的思想
可以将复杂的事情简单化
将程序员从执行者转换成了指挥者
完成需求时:
先要去找具有所需的功能的对象来用。
如果该对象不存在,那么创建一个具有所需功能的对象。
这样简化开发并提高复用。
面向对象开发设计特征
开发的过程:其实就是不断的创建对象,使用对象, 指挥对象做事情。
设计的过程:其实就是在管理和维护对象之间的关系。
面向对象的特征:
封装(encapsulation)
继承(inheritance)
多态(polymorphism)
面向对象编程的优点
提高代码复用性。
使用者无需关心具体细节。
转变程序员角色,更加符合人的思维习惯。
6.多态
多态的定义:多态是指同一种行为具有多个不同的表现形式或形态的能力。在Java中,多态是指一个对象的实际类型可以是其父类或接口类型,但在运行时会根据其实际类型来调用相应的方法。
多态的实现方式
继承实现多态
在继承中,子类可以继承父类的方法并且可以重写父类的方法。当父类有一个方法被子类重写后,父类引用指向子类对象时,调用该方法时会调用子类的方法。
接口实现多态
在接口中,一个类可以实现多个接口。当一个类实现了多个接口时,可以使用接口类型的引用指向该类的对象,从而实现多态。
方法重载实现多态
方法重载是指在同一个类中定义多个同名方法,但参数列表不同。当调用这些方法时,Java会根据方法名和参数列表来确定要调用的方法。
方法覆盖实现多态
方法覆盖是指子类重写父类的方法,使得在调用方法时会优先调用子类的方法。方法覆盖常常与继承相结合使用,用于实现多态。
内部类实现多态
内部类是指一个类定义在另一个类的内部。Java中有四种内部类:成员内部类、静态内部类、局部内部类和匿名内部类。其中成员内部类最常用,可以实现多态。
Java中实现多态的方式有多种,包括继承、接口、方法重载、方法覆盖和内部类等。在使用多态时,需要注意代码的可读性和维护性,并且需要针对具体的应用场景选择合适的实现方式。
在Java中,多态是一个非常重要的概念。它是指同一个方法或者类可以表现出不同的行为。Java中实现多态的方式有多种,包括继承、接口、方法重载、方法覆盖和内部类等。其中,继承和接口是最常见的实现多态的方式。当子类继承父类或者实现了某个接口时,子类可以重写父类的方法或者实现接口的方法,使得在调用方法时会优先调用子类的方法。这种方式可以提高代码的可扩展性、可维护性和可读性,使得代码更加灵活和易于修改。此外,方法重载和方法覆盖也可以实现多态,它们是在同一个类中实现多态的方式。而内部类也可以实现多态,通过内部类的方式可以在一个类中定义多个同名方法,但参数列表不同,从而实现多态。总的来说,多态是Java中的一个核心概念,对于理解和使用Java编程语言非常重要。
7.抽象类和接口
一、抽象类
1.抽象类的定义
概述:我们创建一个动物类,并且在这个类中创建动物对象,但是当你提到动物类,你并不知道我说的是什么动物,只有看到了具体的动物,你才知道这是什么动物,所以说动物本身并不是一个具体的事物,而是一个抽象的事物。只有真正的猫,狗才是具体的动物,同理我们也可以推理不同的动物,他们的行为习惯应该是不一样的,所以我们不应该在动物类中给出具体体现,而是给出一个声明即可。
概念:如果一个类中没有包含足够的信息来描绘一个具体的对象,这样的类就是抽象类。
2.如何定义一个抽象类
在Java中,一个类如果被 abstract 修饰称为抽象类,抽象类中被 abstract 修饰的方法称为抽象方法,抽象方法不用
给出具体的实现体。
关于抽象类的细节
(1)抽象类和普通类不一样,抽象类可以包含抽象方法。
(2)抽象方法是使用abstract修饰的(该方法不能被具体实现)。
(3)抽象类不能被实例化。
(4)如果一个普通类继承了一个抽象类,此时必须在普通类里面重写抽象类里面的抽象方法,否则报错。
(5)如果一个抽象类A继承了抽象类B,此时类A当中不需要重写类B中的抽象方法,但如果类A再被普通类继承就需要重写类B中的抽象方法。
(6)抽象方法不能是private修饰。
(7)抽象方法也不能被final、static修饰,因为该类被继承,此方法还要重写。
(8)重写抽象方法也要遵守重写的规则(public>protected>default>private)。
4.抽象类的作用
讲到这里,可能很多人会说,这抽象类怎么这么复杂,明明普通类就能搞定的事情,为什么还要存在抽象类?
其实这里是因为实际工作不应该由父类完成, 而应由子类完成. 那么此时如果不小心误用成父类
了, 使用普通类编译器是不会报错的. 但是父类是抽象类就会在实例化的时候提示错误, 让我们尽早发现问题。
二、接口
1.接口的概念
概念:接口(Interface),在Java编程语言中是一个抽象类型,是抽象方法的集合,接口用interface来声明,从而继承接口的抽象方法,在Java中,接口可以看成是:多个类的公共规范,是一种引用数据类型。
2.语法形式
接口的定义格式与定义类的格式基本相同,将class关键字换成 interface 关键字,就定义了一个接口.
interface A { public abstract void func1(); void func2(); }注:func1和func2的修饰访问权限符都是一样的,都是public abstract.
3.关于接口的细节
(1)接口当中的成员方法不能有具体的实现.
(2)从JDK1.8开始,允许在接口中有可以实现的方法,但只能被default修饰.
(3)接口中可以实现静态方法.
(4)接口中的成员变量默认是public static final 修饰的.
(5)接口也不能被实例化.
A a = new A();//会报错的
(6)类和接口之间用implements来实现多个接口,类中必须重写接口当中的抽象方法,其他的方法可以选择重写或者不重写.
(7)子类重写抽象方法,必须是public修饰(因为抽象方法默认是public abstract修饰,所以子类只能为public)
(8)接口当中不能有静态代码块和构造方法( 接口中每一个方法也是隐式抽象的,接口中的方法会被隐式的指定为 public abstract(只能是 public abstract,其他修饰符都会报错),所以不能含有静态代码块以及静态方法,不能有构造方法原因是因为接口不能被实例化所以就不能有构造方法) .
(9)如果一个类没有实现接口当中所有的抽象方法,则此类必须设置为抽象类(用abstract修饰),如果这个抽象类被其他类继承必须要重写.
4.代码演示
interface A { void func1(); } class B implements A { @Override public void func1() { } }
一个类也可以实现多个接口,使用逗号隔开.
5.接口的使用
我们知道,如果某个设备需要向电脑中读取或者写入某些东西,这些设备一般都是采用USB方式与电脑连接的,我们发现,只要带有USB功能的设备就可以插入电脑中使用了,那么我们可以认为USB就是一种功能(接口),只要实现了USB标准的设备我们就认为它已经拥有了USB这种功能。
6.实现多个接口
在Java中,类和类之间是单继承的,一个类只能有一个父类,即Java中不支持多继承,但是一个类可以实现多个接
口。
7.接口之间的继承
在Java中,类和类之间是单继承的,一个类可以实现多个接口,接口与接口之间可以多继承,使用extends符号。即:用接口可以达到
多继承的目的。
三、抽象类和接口的区别
核心区别: 抽象类中可以包含普通方法和普通字段, 这样的普通方法和字段可以被子类直接使用(不必重写), 而接口中
不能包含普通方法, 子类必须重写所有的抽象方法.
区别抽象类(abstract)接口(interface)结构组成普通类(普通类能包含的抽象类都有)+抽象方法抽象方法+全局变量权限各种权限public子类使用使用extends继承抽象类使用implements实现接口关系一个抽象类可以实现多个接口一个接口可以使用extends继承多个接口子类限制一个子类只能继承一个抽象类一个子类可以实现多个接口
内部类的概述:
8.内部类的概述
一.内部类概述
就是一个类中定义一个类。
举例:在一个类A的内部定义一个类B,类B就被称为内部类
二、内部类的格式:
public class 类名{
修饰符 class 类名{
}
}
public class sum{
public class sum2{
}
}
三、内部类的访问特点:
1.内部类可以直接访问外部类的成员,包括私有
2.外部类要访问内部类的成员,必须创建对象。
public class sum{
public class sum2{
sum s = new sum();
}
}
四、成员内部类:
1.按照内部类在类中定义的位置不同,可以分为如下两种形式:
①在类的成员位置:成员内部类
②在类的局部位置:局部内部类
2.成员内部类,外界如何创建对象使用呢?
①格式:外部类名.内部类名 对象名 = new 外部类对象.new 内部类对象;
②范例:sum.sum1 s = new sum().new sum1();
③一般内部类都是用private来修饰的而不是public,怎么调用呢?
④格式:外部类名 对象名 = new 外部类对象;
⑤范例:sum1 s = new sum1();
public class sum{
public class sum2{
sum s = new sum();
}
}
public class sum2{
sum.sum2 s = new sum().new sum1();
}
五、局部内部类:
1.局部内部类是在方法中定义的类,所以外界是无法直接使用,需要在方法内部创建对象并使用
2.该类可以直接访问外部类的成员,也可以访问方法内的局部变量
public class sum{
public void eat(){
public class sum1{
sum s = new sum();
}
}
}
六、匿名内部类:
1.匿名内部类的前提:存在一个类或者接口,这里的类可以是具体类也可以是抽象类
2.格式:
new 类名或者接口名(){
重写方法;
};
public interface sum{
public abstract void num();
}
new sum(){
public void num(){
System.out.println("匿名内部类");
}
}
3.本质:是一个继承了该类或实现了该接口的子类匿名对象
4.想要调用匿名类格式:
类名或者接口名 对象名 = new 类名或者接口名(){ 重写方法;
};
public interface sum{
public abstract void num();
}
sum s = new sum(){
public void num(){
System.out.println("匿名内部类");
}
}