- 类:对现实世界中某类事物的描述,是抽象的,概念上的定义。
- 对象:事物具体存在的个体。
类:
对某类事物的普遍一致性特征、功能的抽象、描述和封装,是构造对象的模版或蓝图,用 Java 编写的代码都会在某些类的内部。类之间主要有:依赖、聚合、继承等关系。
在Java中定义类,使用关键字class完成。语法如下:
class 类名称 {
属性 (变量) ;
行为 (方法) ;
}
对象:
使用 new 关键字或反射技术创建的某个类的实例。同一个类的所有对象,都具有相似的数据(比如人的年龄、性别)和行为(比如人的吃饭、睡觉),但是每个对象都保存着自己独特的状态,对象状态会随着程序的运行而发生改变,需要注意状态的变化必须通过调用方法来改变,这就是封装的基本原则。
格式一:声明并实例化对象
类名称 对象名称 = new 类名称 () ;
(2)格式二:先声明对象,然后实例化对象:
类名称 对象名称 = null ;
对象名称 = new 类名称 () ;
new一个类名,就会得到一个对象,而这个对象的类型就是这个类名的类型
比如说:Car car=new Car();//就是通过new一个Car类名,得到car这个对象,而这个对象就是Car类型的
2:类必须先定义才能使用。类是创建对象的模板,创建对象也叫类的实例化。
package com.cnblogs;//定义包的格式,关键词package,包的名字最规范的格式是域名的反写,比如com.什么
public class People {//class关键字,定义类的关键字,People是类的名称
public String name;//类的属性
public String sex;
public int age;
//类的方法
public void sleep(){
System.out.println("人疲倦的时候喜欢睡觉觉");
}
public void eat(){
System.out.println("人饥饿的时候喜欢吃饭饭");
}
public static void main(String[] args) {//主函数
People p=new People();//对象的实例化
p.eat();//调用类的方法
p.sleep();
}
}
当一个实例化对象产生之后,可以按照如下的方式进行类的操作:
对象.属性:表示调用类之中的属性;
对象.方法():表示调用类之中的方法。
Java包(package)
包主要用来对类和接口进行分类。当开发Java程序时,可能编写成百上千的类,因此很有必要对类和接口进行分类。
包的作用
1、把功能相似或相关的类或接口组织在同一个包中,方便类的查找和使用。
2、如同文件夹一样,包也采用了树形目录的存储方式。同一个包中的类名字是不同的,不同的包中的类的名字是可以相同的,当同时调用两个不同包中相同类名的类时,应该加上包名加以区别。因此,包可以避免名字冲突。
3、包也限定了访问权限,拥有包访问权限的类才能访问某个包中的类。
Import语句
在Java中,如果给出一个完整的限定名,包括包名、类名,那么Java编译器就可以很容易地定位到源代码或者类。Import语句就是用来提供一个合理的路径,使得编译器可以找到某个类。
例如,下面的命令行将会命令编译器载入java_installation/java/io路径下的所有类
import java.io.*;
面向过程的思想和面向对象的思想
面向对象和面向过程的思想有着本质上的区别, 作为面向对象的思维来说,当你拿到一个问题时,你分析这个问题不再是第一步先做什么,第二步再做什么,这是面向过程的思维,你应该分析这个问题里面有哪些类和对象,这是第一点,然后再分析这些类和对象应该具有哪些属性和方法。这是第二点。最后分析类和类之间具体有什么关系,这是第三点。
面向对象有一个非常重要的设计思维:合适的方法应该出现在合适的类里面
封装
- 良好的封装能够减少耦合。
- 类内部的结构可以自由修改。
- 可以对成员进行更精确的控制。
- 隐藏信息,实现细节,方便修改和实现。
- 只能通过特定的方法访问数据
封装的代码实现:
属性前+private:该属性只能在当前类内部被访问;
在类外对private属性访问需要:创建getter/setter操作接口取值和赋值:
package com.imooc.animal;
/**
* 宠物猫类
* @author zhangziwei
*
*/
public class Cat {
//修改属性的可见性--private限定只能在当前类访问
private String name;
int month;
double weight;
String species;
public Cat(){
System.out.println("无参数构造方法!");
}
//创建get/set方法
//在get和set方法中添加对属性的限制
public void setName(String name){
this.name=name;
}
public String getName(){
return "我是一只名叫"+this.name+"的猫咪";
}
}
package com.imooc.animal;
public class CatTest {
public static void main(String[] args){
//对象实例化
//Cat one=new Cat("花花",2,1000,"英国短毛猫");
Cat one=new Cat();
one.setName("花花");
System.out.println("昵称:"+one.getName());
}
继承
继承的概念:
继承在本职上是特殊——一般的关系,即常说的is-a关系。子类继承父类,表明子类是一种特殊的父类,并且具有父类所不具有的 一些属性或方法。
1、子类拥有父类非private的属性和方法。
2、子类可以拥有自己属性和方法,即子类可以对父类进行扩展。
3、子类可以用自己的方式实现父类的方法。
Java继承的语法格式:
Java继承的关键字是:extends
public class 子类名 extends 父类名{...}
如: public class UNStudent extends Student {…}
注:1.子类又称超类,拓展类 ;父类又称基类。
-
Java中类的继承只能是单继承(单根继承),即一个类只能继承一个父类,但是一个类可以由多个类来继承它。
-
Java会给每一个没有设置父类的类,自动添加一个父类就是Object 。
子类继承父类的结果:
-
子类继承父类后,继承到了父类所有的属性和方法。 注:是所有
-
子类可调用的方法也要看情况而定:
-
子类和父类在同一个包下时 “子类和子类的对象”可以调用父类的默认的,受保护的,公有的属性以及方法
-
子类和父类在不同的包下时,在子类中可以调用受保护的,公有的属性以及方法,而子类的对象可以调用受保护的,公有的属性以及方法。
-
方法的重写
-
当子类和父类都有某种方法,而子类的方法更加要求细致,或者实现功能不同,就需要方法的重写
-
重写条件:
1.必须要有继承关系;
2.重写方法时子类方法的访问修饰符必须要大于或者等于父类方法的访问修饰符;
3.重写方法时子类方法的返回值类型,方法名,参数都必须要和父类的一致。
-
子类重写方法时的访问修饰符可以大于或者等于父类方法的访问修饰符。
-
重写后的方法会被优先调用。
方法的重载
Java重载是指Java允许在一个类中,存在多个拥有相同的名字,但参数不同的方法,编译器会根据实际情况挑选出正确的方法,如果编译器找不到匹配的参数或者找出多个可能的匹配就会产生编译时错误,这个过程被称为重载的解析。
重载包括:普通方法的重载和构造方法的重载
方法:即函数(文中我们统称之为“方法”),是一个固定的一个程序段,或称其为一个子程序,它在可以实现固定运算功能。而且,同时还带有一个入口和一个出口,所谓的入口,就是函数所带的各个参数,我们可以通过这个入口,把函数的参数值传入子程序,供计算机处理;所谓出口,就是指函数的返回值,在程序段执行之后,由此返回值将值传回给调用它的程序。
通常地,一个类可以有多个重载方法,可根据不同的需求来设计类中不同的重载方法。其中,参数个数、类型、甚至不同类型参数的顺序等的的不同均为对同一个方法的不同重载。
public void show(); //无参方法
public void show(String name); //重载show方法,一个字符串参数
public void show(String name, int age); //重载show方法,两个参数
public void show(int age, String name); //重载show方法,两个参数顺序不同
判断方法重载的依据:
1、必须是在同一个类中
2、方法名相同
3、方法参数的个数、顺序或类型不同
4、与方法的修饰符或返回值没有关系
自动转型
自动转型的实现要求有继承关系
格式如下:父类名 对象名 = new 子类构造方法();
如:Student stu = new UNStudent();
而强制转型格式如下:
子类名 对象名 = (子类名)父类对象名 如:UNStudent un = (Student)stu;
-
自动转型可以拓宽方法的作用访问域,在使用自动转型后,子类自己定义的方法是不能在自动转型后执行;
-
原因是因为Java的编译机制,它会优先判断父类中是否存在该方法,如果存在则通过编译,如果不存在则报错。
第二种自动转型:转型后只需要不同类的不同对象调用想吐的方法,很方便!
/**访问修饰符 返回值数据类型 方法名(父类类型 参数名,...){
调用方法。
}
父类名 对象名 = new 子类名();
子类名 对象名 = new 子类名();
方法名(对象名);
*/
比如拿到驾驶证为A2的人,可以驾驶重型货车,当然可以驾驶 大型货车,中型货车 ,小型货车,小客车,小轿车,摩托车… 可以选择第二种自动转型的方法,便于调用同一个方法
自动转型好处:1.减少冗余代码;2.在方法设置参数时,扩大访问范围。
多态
多态是由方法重载,继承,方法重写,自动转型等技术的组合。
概念:
对象在不同时刻表现出来的不同状态。
多态的定义
指允许不同类的对象对同一消息做出响应。即同一消息可以根据发送对象的不同而采用多种不同的行为方式。(发送消息就是函数调用)
实现多态的技术
动态绑定(dynamic binding),是指在执行期间判断所引用对象的实际类型,根据其实际的类型调用其相应的方法
多态的前提:
- 要有继承或者实现关系。
- 要有方法的重写。
- 要有父类引用指向子类对象。
- 程序中的体现:
- 父类或者接口的引用指向或者接收自己的子类对象。
好处和作用:
1.可替换性,对于已存在的代码具有可替换性
2.可扩充性,增加的新子类不影响已经存在的类的多态性,继承性及其他特性
3.接口性,多态是超类通过方法签名,向子类提供共同接口
弊端:
父类调用的时候只能调用父类里的方法,不能调用子类的特有方法,因为你并不清楚将来会有什么样的子类继承你。
多态的成员特点:
- 成员变量:编译时期:看引用型变量所属的类中是否有所调用的变量;
- 运行时期:也是看引用型变量所属的类是否有调用的变量。
成员变量无论编译还是运行都看引用型变量所属的类,简单记成员变量,编译和运行都看等号左边。 - 成员方法:编译时期:要查看引用变量所属的类中是否有所调用的成员;
- 运行时期:要查看对象所属的类中是否有所调用的成员。如果父子出现同名的方法,会运行子类中的方法,因为方法有覆盖的特性。
编译看左边运行看右边。 - 静态方法:编译时期:看的引用型变量所属的类中是否有所调用的变量;
- 运行时期:也是看引用型变量所属的类是否有调用的变量。
编译和运行都看等号左边。
一定不能够将父类的对象转换成子类类型!
父类的引用指向子类对象,该引用可以被提升,也可以被强制转换。
多态自始至终都是子类对象在变化!
/*
对象的多态性:动物 x = new 猫();
函数的多态性:函数重载、重写
1、多态的体现
父类的引用指向了自己的子类对象
父类的引用也可以接收自己的对象
2、多态的前提
必须是类与类之间只有关系,要么继承或实现
通常还有一个前提,存在覆盖
3、多态的好处
多态的出现大大的提高了程序的扩展性
4、多态的弊端
只能使用父类的引用访问父类的成员
5、多态的应用
6、注意事项
*/
/*
需求:
猫,狗。
*/
abstract class Animal
{
abstract void eat();
}
class Cat extends Animal
{
public void eat()
{
System.out.println("吃鱼");
}
public void catchMouse()
{
System.out.println("抓老鼠");
}
}
class Dog extends Animal
{
public void eat()
{
System.out.println("吃骨头");
}
public void kanJia()
{
System.out.println("看家");
}
}
class DuoTaiDemo
{
public static void main(String[] args)
{
function(new Cat());
function(new Dog());
Animal a = new Cat();//向上转型
a.eat();
Cat c = (Cat)a;//向下转型
c.catchMouse();
}
public static void function(Animal a)
{
a.eat();
//用于子类型有限
//或判断所属类型进而使用其特有方法
if(a instanceof Cat)
{
Cat c = (Cat)a;
c.catchMouse();
}
else if(a instanceof Dog)
{
Dog c = (Dog)a;
c.kanJia();
}
}
}
执行结果为:
吃骨头
看家
吃鱼
抓老鼠
抽象
抽象就是从多个事物中将共性的,本质的内容抽象出来。
抽象类:
Java中可以定义没有方法体的方法,该方法的具体实现由子类完成,该方法称为抽象方法,包含抽象方法的类就是抽象类。
由来:
多个对象都具备相同的功能,但是功能具体内容有所不同,那么在抽取过程中,只抽取了功能定义,并未抽取功能主体,那么只有功能声明,没有功能主体的方法称为抽象方法。
抽象类的使用规则如下;
-
抽象方法必须为public或者protected(因为如果为private,则不能被子类继承,子类便无法实现该方法),缺省情况下默认为public;
-
抽象类不能直接实例化,需要依靠子类采用向上转型的方式处理;
-
抽象类必须有子类,使用extends继承,一个子类只能继承一个抽象类;
-
子类(如果不是抽象类)则必须覆写抽象类之中的全部抽象方法(如果子类没有实现父类的抽象方法,则必须将子类也定义为为abstract类。);
抽象类特点:
- 抽象方法一定在抽象类中;
- 抽象方法和抽象类都必须被abstract关键字修饰;
- 抽象类不可以用new创建对象,因为调用抽象方法没意义;
- 抽象类中的抽象方法要被使用,必须由子类复写其所有的抽象方法后,建立子类对象调用; 如果子类只覆盖了部分的抽象方法,那么该子类还是一个抽象类;
- 抽象类中可以有抽象方法,也可以有非抽象方法,抽象方法用于子类实例化;
- 如果一个类是抽象类,那么,继承它的子类,要么是抽象类,要么重写所有抽象方法。
- 特殊:抽象类中可以不定义抽象方法,这样做仅仅是不让该类建立对象。
抽象类的成员特点:
- 成员变量:可以是变量,也可以是常量;
- 构造方法:有构造方法;
- 成员方法:可以是抽象方法,也可以是非抽象方法。
抽象类注意事项:
- 抽象类不能被实例化,为什么还有构造函数?
只要是class定义的类里面就肯定有构造函数。抽象类中的函数是给子类实例化的。
- 一个类没有抽象方法,为什么定义为抽象类?
不想被继承,还不想被实例化。
-
抽象关键字abstract不可以和哪些关键字共存?
- final:如果方法被抽象,就需要被覆盖,而final是不可以被覆盖,所以冲突。
- private:如果函数被私有了,子类无法直接访问,怎么覆盖呢?
- static:不需要对象,类名就可以调用抽象方法。而调用抽象方法没有意义。
publicabstractclass SupClass {//父类
publicvoid print() {
System.out.println("我不是抽象方法!");
}
publicabstractvoid println();//抽象方法;没有方法体,
}
publicclass SubClass extends SupClass {
publicvoid println() {
System.out.println("我已把父类中的抽象方法覆盖拉");
}
}
publicclass Test {
publicstaticvoid main(String[] args) {
SupClass sub = new SubClass();//多态测试
sub.print();
sub.println();
}
}
答案;
我不是抽象方法!
我已把父类中的抽象方法覆盖拉
接口
接口是抽象方法和常量值的集合。从本质上讲,接口是一种特殊的抽象类,这种抽象类只包含常量和方法的定义,而没有变量和方法的实现。
格式:interface 接口名{}
接口的出现将”多继承“通过另一种形式体现出来,即”多实现“。
实现(implements)
格式:public 修饰符 class 类名 implements 接口名 {}
- 修饰符:可选,用于指定接口的访问权限,可选值为public。如果省略则使用默认的访问权限。
- 接口名:必选参数,用于指定接口的名称,接口名必须是合法的Java标识符。一般情况下,要求首字母大写。
- extends 父接口名列表:可选参数,用于指定要定义的接口继承于哪个父接口。当使用extends关键字时,父接口名为必选参数。
- 方法:接口中的方法只有定义而没有被实现。
特点:
- 接口不能被实例化。
- 一个类如果实现了接口,要么是抽象类,要么实现接口中的所有方法。
接口的成员特点:
-
接口中的成员修饰符是固定的!
-
成员常量:public static final,接口里定义的变量是全局常量,而且修饰符只能是这三个关键字,都可以省略,常量名要大写。
-
成员方法:public abstract,接口里定义的方法都是抽象的,两个修饰符关键字可省略。
推荐:永远手动给出修饰符。
继承与实现的区别:
- 类与类之间称为继承关系:因为该类无论是抽象的还是非抽象的,它的内部都可以定义非抽象方法,这个方法可以直接被子类使用,子类继承即可。只能单继承,可以多层继承。((class))
- 类与接口之间是实现关系:因为接口中的方法都是抽象的,必须由子类实现才可以实例化。可以单实现,也可以多实现;还可以在继承一个类的同时实现多个接口。((class) extends (class) implements (interface1,interface2…))
- 接口与接口之间是继承关系:一个接口可以继承另一个接口,并添加新的属性和抽象方法,并且接口可以多继承。((interface) extends (interface1,interface2…))
关于接口的几个重点
我们不能直接去实例化一个接口,因为接口中的方法都是抽象的,是没有方法体的,这样怎么可能产生具体的实例呢?但是,我们可以使用接口类型的引用指向一个实现了该接口的对象,并且可以调用这个接口中的方法。因此,上图中最后的方法调用我们还可以这样写:(实际上就是使用了Java中多态的特性)
public class Main {
public static void main(String[] args) {
//生成一个实现可USB接口(标准)的U盘对象
//但是使用一个接口引用指向对象
//USB接口类引用可以指向一个实现了USB接口的对象
USB youPan = new YouPan();
//调用U盘的read( )方法读取数据
youPan.read();
//调用U盘的write( )方法写入数据
youPan.write();
//生成一个实现可USB接口(标准)的键盘对象
//但是使用一个接口引用指向对象
//USB接口类引用可以指向一个实现了USB接口的对象
USB jianPan = new JianPan();
//调用键盘的read( )方法读取数据
jianPan.read();
//调用键盘的write( )方法写入数据
jianPan.write();
}
}
- 一个类可以实现不止一个接口。
- 一个接口可以继承于另一个接口,或者另一些接口,接口也可以继承,并且可以多继承。
- 一个类如果要实现某个接口的话,那么它必须要实现这个接口中的所有方法。
- 接口中所有的方法都是抽象的和public的,所有的属性都是public,static,final的。
- 接口用来弥补类无法实现多继承的局限。
- 接口也可以用来实现解耦。
抽象类和接口的区别:
成员变量
- 抽象类能有变量也可以有常量
- 接口只能有常量
成员方法
- 抽象类可以有非抽象的方法,也可以有抽象的方法
- 接口只能有抽象的方法
构造方法
- -抽象类有构造方法
- -接口没有构造方法
类与抽象类和接口的关系
- 类与抽象类的关系是继承 extends
- 类与接口的关系是实现 implements
接口的思想特点:
- 接口是对外暴露的规则;
- 接口是程序的功能扩展;
- 接口的出现降低耦合性;(实现了模块化开发,定义好规则,每个人实现自己的模块,大大提高了开发效率)
- 接口可以用来多实现;
- 多个无关的类可以实现同一个接口;
- 一个类可以实现多个相互直接没有关系的接口;
- 与继承关系类似,接口与实现类之间存在多态性。
内部类
将一个类定义在另一个类里面,里面的那个类就称为内部类。内部类的出现,再次打破了Java单继承的局限性。
访问特点:
- 内部类可以直接访问外部类的成员,包括私有成员。
- 外部类要访问内部类的成员,必须要建立内部类的对象。
内部类分类及共性:
共性:
- 内部类仍然是一个独立的类,在编译之后会内部类会被编译成独立的.class文件,但是前面冠以外部类的类名和$符号。
- 内部类不能用普通的方式访问。内部类是外部类的一个成员,因此内部类可以自由地访问外部类的成员变量,无论是否是private的。
成员内部类
- 在外部类中有成员变量和成员方法,成员内部类就是把整个一个类作为了外部类的成员;
- 成员内部类是定义在类中方法外的类;
- 创建对象的格式为:
外部类名.内部类名 对象名 = 外部类对象.内部类对象;
- 成员内部类之所以可以直接访问外部类的成员,那是因为内部类中都持有一个外部类对象的引用:
外部类名.this;
- 成员内部类可以用的修饰符有final,abstract,public,private,protected,static.
静态内部类
-
静态内部类就是成员内部类加上静态修饰符static,定义在类中方法外。
-
在外部类中访问静态内部类有两种场景:
-
在外部类中访问静态内部类中非静态成员:外部类名.内部类名 对象名 = 外部类名.内部对象,需要通过创建对象访问;
-
在外部类中访问静态内部类中的静态成员:同样可以使用上面的格式进行访问,也可以直接使用外部类名.内部类名.成员。
局部内部类
-
局部内部类是定义在方法中的类。
-
方法内部类只能在定义该内部类的方法内实例化,不可以在此方法外对其实例化。
-
方法内部类对象不能使用该内部类所在方法的非final局部变量。
-
可以用于方法内部类的修饰符有final,abstract;
-
静态方法中的方法内部类只能访问外部的静态成员。
匿名内部类
- 匿名内部类是内部类的简化写法,是建立一个带内容的外部类或者接口的子类匿名对象。
- 前提:内部类可以继承或实现一个外部类或者接口。
- 格式:
new 外部类名或者接口名(){重写方法};
- 通常在方法的形式参数是接口或者抽象类,并且该接口中的方法不超过三个时,可以将匿名内部类作为参数传递。