1、面向对象
一切客观存在的事物都是对象,万物皆对象。
1.1对象包括特征和行为。
特征:称为属性,一般为名词,代表对象有什么。
行为:称为方法,一般为动词,代表对象能做什么。
1.2什么是类?(请看下图)
1.3类的定义:
public class Dog{
String breed;//品种
int age;//年龄
String sex;//性别
String furColor;//毛色
public void eat(){
System.out.println("eating...");
}//一个吃的方法
}
属性与方法的定义:
属性:通过变量表示,又称实例变量
语法:数据类型 属性名;
位置:类的内部,方法的外部。
方法:通过方法表示,又称实例方法。
语法:
public 返回值类型 方法名(形参){
//方法的主体
}
1.4对象的创建
public class TestCreateObject{
public static void main(String[] args){
Dog myDog=new Dog();//基于Dog类创建对象
myDog.breed="斗牛犬";
myDog.age=2;
myDog.sex="公";
myDog.furColor="黑白";//访问属性并赋值
myDog.eat();
myDog.sleep();//访问方法
}
}
1.5类与对象的关系
类:定义了对象应具有的特征和行为,类是对象的模板
对象:拥有多个特征和行为的实体,对象是类的实例
1.6实例变量与局部变量的区别
1.7方法的重载
在类里面可以拥有相同的方法名,但这些方法的参数列表以及参数类型不一样。这种方式构造的方法就叫方法重载。
1.8构造方法
构造方法是类的一个重要方法。
在实例化一个对象的时候,首先调用的就是类的构造方法,也必须调用类的构造方法才能创建对象。
构造方法的创建方式:
public class Dog{
int age;
public Dog(){
}//默认构造方法,这个构造方法可以省略不写,会默认添加
public Dog(int age){
this.age=age;//这里使用了this关键字,代表本对象。
}//这是个带参构造方法,需要自己创建和调用
}
构造方法的语法:
public 方法名(与类名一模一样)(参数列表){
方法体;
}
学习遇到的问题:
1、定义了一个学生类,并且创建了这个学生类的对象数组,如:
Student[] stu=new Student[5];// 然后对他进行赋值
stu[0].name="张三";//学生类里面有个姓名属性
上面的代码执行过程中出现空指针错误。 解决:赋值方式应改为:
Student stu1=new Strudent();//创建一个对象
stu1.name="张三";//给对象属性赋值
stu[0]=stu1;//之后把这个对象赋值到数组
错误原因: student[] stu=new Student[5]; 误以为这个数组创建就是创建了拥有五个对象的数组。其实这只是在堆里面开辟了五个空间用于存放学生对象,并没有创建对象。 # 2、三大特性 封装、继承、多态
2.1封装
2.1.1封装的必要性:
2.1.2什么是封装
把类里面的属性的访问权限设置成私有属性,在对外提供一个公共访问的修改方法,在方法里面写上必要的控制语句,使得属性的值在我们需要的范围内。
例:
class Student{
private String name;
private int age;
public void setName(String name){
this.name=name;
}
public String getName(){
return this.name;
}
public void setAge(int age){
if(age<0||age>100){//一个学生的年龄不可能小于零,又限制不得超过100岁
System.out.println("年龄不合法,赋值失败");
}else{
this.age=age;
}
}
public int getAge(){
return this.age;
}
}
2.2继承
2.2.1程序中的继承
程序中的继承,是类与类之间特征和行为的一种赠与或获得
两个类之间的继承关系,必须满足“is a” 的关系。
如图:
2.2.2继承的语法
语法:calss子类extends父类{}//定义子类是,显示继承父类
应用:产生继承关系之后,子类可以使用父类的属性何方法,也可以定义子类独有的方法和属性
好处:既可以提高代码的复用性,又可以提高代码的可扩展性
2.2.3继承的特点
java继承都是单继承,但是可以多级继承,比如父类也继承了它的父类,子类就业相当于继承了祖辈类。但是私有方法与属性不可继承
2.2.4方法重写
当父类有一个方法子类不适用,但是有需要这个行为,于是子类可以写个一摸一样的方法,但是方法体不一样,这个就是重写。
#2.3、多态
2.3.1多态的解释:
一件事在不同的人眼里可能出现不一样的效果,这就是多态的照展现。
2.3.2在程序里面的实现方式是:
首先声明个父类,父类里面有一个方法。
然后声明多个子类继承这个父类,并且重写这个方法。
调用的时候用父类声明指向子类对象,然后用这个声明调用这个方法就能实现不同的功能。
2.3.3拆箱与装箱
装箱(向上转型)
其实这个父类引用指向子类对象就是一个装箱过程。
这时候这个引用只能调用父类的方法与属性,有时候我们需要调用子类独有的方法属性时,不能直接调用,这时候就需要拆箱
拆箱(向下转型)
父类引用强制转化为子类引用。
但这个父类引用所指的对象必须是这个子类的对象,否则会报错(避免的方法就是先检测,检测方法是关键字instanceof)。这时候这个引用既能调用子类的特有的属性与方法还能调用父类的属性与方法。
强调:此时的这个父类引用与子类引用指向的是同一个对象,一个改变另一个得到的数据也会改变。
3、三大修饰符
抽象、静态、最终
3.1、抽象
3.1.1什么是抽象
似是而非的,却又不是;具备某种对象的特征,但是不完整。
在程序中,如果这个类是抽象类,那么这个类不能被创建对象
3.1.2抽象类的创建
3.1.3抽象类的作用
抽象方法只能写在抽象类里面,抽象类不一定有抽象方法。
抽象类被继承,那么这个抽象类的所有抽象方法都要子类重写,假如子类也是个抽象类,那么这个子类可重写方法,也可跳过,但遇到非抽象子类则必须把父辈未重写的抽象方法全部重写。
3.2、静态属性
3.2.1实例属性与静态属性的对比
3.2.2什么是静态
概念:
静态(static)可以修饰属性和方法。
称为静态属性(类属性)、静态方法(类方法)。
静态成员是全类所有对象共享的成员。
在全类中只有一份,不因创建多个对象而产生多份。
不必创建对象,可直接通过类名访问。
静态方法就是在普通方法的返回值类型前面加上static
静态方法与静态属性的调用可直接使用类名点属性或者方法。不用创建对象。
3.3final(最终)
3.3.1什么是最终
概念:最后的,不可更改的。
final可修饰的内容:
类(最终类)
方法(最终方法)
变量(最终变量)
final修饰类:此类不能被继承。
String、Math、System均为final修饰的类,不能被继承。
final修饰方法:此方法不能被覆盖。
意为最终方法,不支持子类以覆盖的形式修改
4、接口
4.1基本使用
概念:接口相当于特殊的抽象类,定义方式、组成部分与抽象类类似。使用interface关键字定义接口。
特点:
- 没有构造方法、不能创建对象
- 只能定义:公开静态常量、公开抽象方法。
案例演示:自定义接口
public interface MyInterface{
String NAME="接口1";
//这个写法是省略写法,十几编译为:
//public static final String NAME="接口1";
void method();
//方法实际编译为:
//public abstract void method1();
}
实现类:
public class Impl implements MyInterface{
@override //这个是重写的意思
public void method(){
System.out.println("method");
}
//把这个方法体重写为输出method
}
测试类
public class TestInterface{
public static void main(String[] args){
MyInterface myInterface=new Impl();
myInterface.method();
}
}
4.2和抽象类的区别
相同点:
可编译成字节码文件。
不能创建对象。
可以作为引用类型。
具备Object类中所定义的方法。
不同点:
所有属性都是公开静态常量,隐式使用public static final修饰。
所有方法都是公开抽象方法,隐式使用public abstract修饰。
没有构造方法、动态代码块、静态代码块。
4.3对接口的理解
从微观上讲:接口是一种能力和约定
接口的定义:代表了某种能力。
方法的定义:能力的具体要求。
比如我创建一个接口,接口名为法术
接口里面有个方法叫做法术攻击
然后写一个实现法术的类,类名叫做火球
类里面重写法术攻击的方法:火球通过集中敌人造成法术伤害。
之后写一个调用类,里面用接口创建一个引用,引用名为安琪拉,再创建一个火球的对象,安琪拉引用指向火球对象,然后使用安琪拉点法术攻击,然后就完成了安琪拉使用火球对敌人造成了法术攻击这一个接口创建、实现并调用的过程。
为什么不使用抽象类而使用接口呢?
答:首先为什么使用抽象类或者接口,应为法术是挺多英雄都有的能力,那些法术英雄只要实现接口或者继承抽象类重写方法就能展现这些法师的能力,这样减少了冗余代码。然后为什么使用接口而不使用类,应为法术并不是所有的英雄都有,类一般存放的是所有子类所共有的属性和方法,所以选择接口。
4.4从宏观上来讲接口是一种标准、一种规范
例如,例如我创建一个接口,接口名为USB
里面有一个名字叫做工作的方法。
然后我设计一个电脑类,电脑类里面有三个USB的接口属性,
再分别设计三个类去实现USB接口,比如U盘、USB电风扇、USB键盘,分别重写工作的方法。
之后在电脑类里面分别创建U盘、等对象。然后把这些对象赋值给电脑的三个USB接口属性(这个就可以看成我把U盘插入电脑的usb接口中)。然后用usb点工作,完成U盘等对象的工作方式。
从这个例子可以看出,接口是一种标准一种规范,假如我的电脑属性用的不是USB接口而是type-c接口那我的U盘等用到usb接口的对象就不能被电脑使用,又或者U盘等使用的不是usb接口,同样电脑也使用不了U盘等对象的功能。
例子的代码展示:
usb接口:
public interface Usb{
void work();
}
电脑类
public class Computer{
private Usb usb1;
private Usb usb2;
private Usb usb3;
public void open() {
System.out.println("电脑开机啦");
if(usb1!=null) {
usb1.work();
}
if(usb2!=null) {
usb2.work();
}
if(usb3!=null) {
usb3.work();
}
}
public Usb getUsb1() {
return usb1;
}
public void setUsb1(Usb usb1) {
this.usb1 = usb1;
}
public Usb getUsb2() {
return usb2;
}
public void setUsb2(Usb usb2) {
this.usb2 = usb2;
}
public Usb getUsb3() {
return usb3;
}
public void setUsb3(Usb usb3) {
this.usb3 = usb3;
}
}
U盘类实现usb接口:
public class Upan implements Usb{
@Override
public void work(){
System.out.println("U盘已接入,可以使用U盘存储文件了");
}
}
电风扇实现usb接口:
public class Fan implements Usb{
@Override
public void servies() {
System.out.println("风扇已接通,可以凉快一下了");
}
}
键盘实现usb接口:
public class KeyBoard implements Usb{
@Override
public void servies() {
System.out.println("键盘已接通,可以使用键盘打字了");
}
}
测试类(对电脑使用接口以及对实现接口类的调用):
public class GameUser {
public static void main(String[] args) {
Computer cp=new Computer();
//先创建一个电脑对象,电脑是接口的使用者
cp.open();
//开机之后没有任何usb接口有对象接入
Upan m=new Upan();
//创建一个U盘对象,U盘是接口的实现者,这个接口有什么功能靠U盘决定
cp.setUsb1(m);
//在这里把U盘与usb1接口连上
Fan f=new Fan();
cp.setUsb2(f);
KeyBoard k=new KeyBoard();
cp.setUsb3(k);
cp.open();
//等做完上面的连接代码之后,再开机,就有三个usb接口连接,然后有不同的功能。
}
}
4.5回调原理
接口回调:现有接口的使用者,后有接口的实现者。
这里引用一句话:
当接口变量调用被类实现的接口中的方法时,就是通知相应的对象调用接口的方法,这一过程称为对象功能的接口回调。
这个接口变量就是电脑的usb接口,被类实现的接口中的方法就是u盘等对象重写的servies方法。
4.6接口的好处:
- 程序的耦合度降低。
- 更自然的使用多态。
- 设计与实现完全分离。
- 更容易搭建程序框架。
- 更容易更换具体实现。
5、内部类
5.1内部类的分类
- 成员内部类
- 静态内部类
- 局部内部类
- 匿名内部类
5.2什么是内部类
概念:在一个类的内部再定义一个完整的类。
特点:
- 编译之后可生成独立的字节码文件。
- 内部类可直接访问外部类的私有成员,而不破坏封装。
- 可为外部类提供必要的内部功能组件。
5.3内部类的介绍
5.3.1成员内部类
顾名思义写在一个类里面的类,它的地位与属性和方法相当,能调用外部类的所有属性和方法外部类调用内部类的属性和方法时也需要创建对象才能调用,这时内部类与普通的内一样,并且内部类也可以继承父类与实现接口。这在另一个方面让Java实现了一个类多继承的功能。
5.3.2静态内部类
我们在java文件中创建的类是不能用static修饰的,但是我们的内部类是可以用static修饰,称它为静态内部类。
静态内部类的特点:
不依赖外部类对象,可直接创建或通过类名访问,可声明静态成员。
只能直接访问外部类的静态成员(实例成员需实例化外部类对象)。
案例演示:
public class Outer {
private String name="xxx";
private int age=18;
//静态内部类:和外部类相同
static class Inner{
private String address="上海";
private String phone="111";
//静态成员
private static int count=1000;
public void show() {
//调用外部类的属性呢
//1先创建外部类对象
Outer outer=new Outer();
//2调用外部类对象的属
System.out.println(outer.name);
System.out.println(outer.age);
//调用静态内部类的属性和
System.out.println(address);
System.out.println(phone);
//调用静态内部类的静态属性
System.out.println(Inner.count);
}
}
}
测试类调用:
public class TestOuter {
public static void main(String[] args) {
//直接创建静态内部类对象
Outer.Inner inner=new Outer.Inner();
//调用方法 inner.show();
}
}
5.3.3局部内部类
定义在外部类方法中,作用范围和创建对象范围仅限于当前方法。
局部内部类访问外部类当前方法中的局部变量时,因无法保障变量的生命周期与自身相同,变量必须修饰为final。
限制类的使用范围。
案例演示:
public class Outer {
private String name="刘德华";
private int age=35;
public void show(final int i) {
//定义局部变量
String address="深圳";
//局部内部类 :注意不能加任何访问修饰符
class Inner{
//局部内部类的属性
private String phone="15588888888";
private String email="liudehua@qq.com";
private final static int count=2000;
public void show2() {
//访问外部类的属性
System.out.println(Outer.this.name);
System.out.println(Outer.this.age);
//访问内部类的属性
System.out.println(this.phone);
System.out.println(this.email);
//访问局部变量,jdk1.7要求:变量必须是常量 final,jdk1.8 自动添加
final System.out.println("深圳");
System.out.println(i);
}
}
//创建局部内部类对象
Inner inner=new Inner();
inner.show2();
}
}
测试类:
public class TestOuter {
public static void main(String[] args) {
Outer outer=new Outer();
outer.show(120);
}
}
5.3.4匿名内部类
没有类名的局部内部类(一切特征都与局部内部类相同)。
必须继承一个父类或者实现一个接口。
定义类、实现类、创建对象的语法合并,只能创建一个该类的对象。
优点:减少代码量。
缺点:可读性较差。
案例演示:
匿名内部类一般就是在实现这个接口,并且使用的机会很少的时候,就暂时性的使用。
定义一个测试接口:
public interface Usb {
//服务
void service();
}
匿名内部类的使用:
public class TestUsb {
public static void main(String[] args) {
//使用匿名内部类优化(相当于创建了一个局部内部类)
Usb usb=new Usb() {
@Override
public void service() {
System.out.println("连接电脑成功,风扇开始工作了....");
}
};
usb.service();
}
}
6、object类
6.1概述
- 超类、基类,所有类的直接或间接父类,位于继承树的最顶层。
- 任何类,如没有书写extends显示继承某个类,都默认直接继承Object类,否则为间接继
承。 - Object类中所定义的方法,是所有对象都具备的方法。
- Object类型可以存储任何对象。
- 作为参数,可接受任何对象。
- 作为返回值,可返回任何对象。
object作为所有类的父类,有挺多方法,我们会用就好
6.2方法介绍
6.2.1 getClass()
public final Class<?> getClass(){…}
返回引用中存储的实际对象类型。
应用:通常用于判断两个引用中实际存储对象类型是否一致。
6.2.2 hashCode()方法
public int hashCode(){…}
返回该对象的十进制的哈希码值。
哈希算法根据对象的地址或字符串或数字计算出来的int类型的数值。
哈希码并不唯一,可保证相同对象返回相同哈希码,尽量保证不同对象返回不同哈希码。
6.2.3 toString()方法
public String toString(){…}
返回该对象的字符串表示(表现形式)。
可以根据程序需求覆盖该方法,如:展示对象各个属性值
6.2.4 equals()方法
public boolean equals(Object obj){…}
默认实现为(this == obj),比较两个对象地址是否相同。
可进行覆盖,比较两个对象的内容是否相同。
equals重写步骤:
比较两个引用是否指向同一个对象。
判断obj是否为null。
判断两个引用指向的实际对象类型是否一致。
强制类型转换。
依次比较各个属性值是否相同
equals方法重写:
public class Student {
private String name;
private int age;
public Student() {
}
public Student(String name, int age) {
super();
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Student [name=" + name + ", age=" + age + "]";
}
@Override public boolean equals(Object obj) {
//1判断两个对象是否是同一个引用
if(this==obj) { return true; }
//2判断obj是否null
if(obj==null) { return false; }
//3判断是否是同一个类型
//intanceof 判断对象是否是某种类型
if(obj instanceof Student) {
//4强制类型转换
Student s=(Student)obj;
//5比较熟悉
if(this.name.equals(s.getName())&&this.age==s.getAge())
{
return true;
}
}
return false;
}
测试学生重写方法equal类:
public class TestStudent {
public static void main(String[] args) {
//1getClass方法
System.out.println("------------1getClass---------");
Student s1=new Student("aaa", 20);
Student s2=new Student("bbb",22);
//判断s1和s2是不是同一个类型
Class class1=s1.getClass();
Class class2=s2.getClass();
if(class1==class2) {
System.out.println("s1和s2属于同一个类型");
}else {
System.out.println("s1和s2不属于同一个类型");
}System.out.println("-----------2hashCode------------");
//2hashCode方法
System.out.println(s1.hashCode());
System.out.println(s2.hashCode());
Student s3=s1;
System.out.println(s3.hashCode());
//3toString方法
System.out.println("-----------3toString------------");
System.out.println(s1.toString());
System.out.println(s2.toString());
//4equals方法:判断两个对象是否相等
System.out.println("-----------4equals------------");
System.out.println(s1.equals(s2));
Student s4=new Student("小明", 17);
Student s5=new Student("小明",17);
System.out.println(s4.equals(s5));
}
}
6.2.5 finalize()方法
- 当对象被判定为垃圾对象时,由JVM自动调用此方法,用以标记垃圾对象,进入回收队列。
- 垃圾对象:没有有效引用指向此对象时,为垃圾对象。
- 垃圾回收: 由GC销毁垃圾对象,释放数据存储空间。
- 自动回收机制:JVM的内存耗尽,一次性回收所有垃圾对象。
- 手动回收机制:使用System.gc(); 通知JVM执行垃圾回收。