1类与对象
面对对象的介绍:
面向对象是一种编程思想面向对象是基于面向过程从面向过程思想演化过来的。
面向过程思想: 在完成功能的时候我们需要关注里面的每一个细节,每个步骤, 并且里面的每个细节每个步骤都要有我们自己亲力亲为,由我们自己去实现。
面向对象思想: 在完成功能的时候,我们只关注结果, 里面的细节,步骤是由别人(对象)帮我们实现的。 面向过程事情是自己做, 面向对象事情是别人做。面向对象思想的好处:
- 可以把复杂的事情简单化。
- 更加符合人类思考的习惯。
- 从执行者变成了指挥者。
类和对象的介绍:
在现实生活中有很多事物,人,学生,老师等。我们可以通过两个方面去描述这些事物(属性和行为)。
属性:是这类事物可以描述的信息,如一个学生的姓名、性别、年龄等
行为:该事物能做什么事情,如学生可以学习,吃法等
在Java中最基本的组成单位是类,我们可以通过类来描述一系列事物。Java类中,属性又称为成员变量,行为又称为成员方法(函数)。
类:用来描述现实事物,是抽象的,比如人,学生等
对象:是类的具体体现,是具体的,如:人是小明,学生为班长。
成员变量与局部变量的区别
1.定义位置不同: 局部变量定义在方法中。 成员变量: 定义在类中方法外。
2. 初始值不同: 局部变量没有初始值,在使用前必须要赋值。 成员变量: 有初始值的,成员变量的初始值和数组元素的初始值一样。
3. 内存位置不同: 局部变量跟随方法保存在栈内存中。 成员变量跟随方法保存在堆内存中。
4.生命周期不同 : 局部变量 当代码执行完定义变量的代码时就会产生 离开自己的作用域该变量就会消失 。成员变量: 在创建对象的时候跟随对象产生, 在对象消失的时候跟随对象消失。
封装
封装指的是隐藏具体的实现,然后提供公共的对外访问方式。
目前代码封装的体现:使用private关键字将属性私有(隐藏), 然后提供了get/set(访问方式)。封装的好处: 1. 提高代码的安全性。 2. 可以提高代码的复用性
构造方法
构造方法作用: 用来在创建对象的时候给属性赋值。
构造方法的格式:
public 构造方法名(参数列表) {
构造方法体;
}
1. 构造方法不需要写返回值类型,连void都不用写
2. 构造方法名必须和类名一致
3. 构造方法不能return任何东西,但是单独写一个return是可以的, return一般省略。
构造方法的调用:
构造方法是在创建对象的时候自动调用的。
new 数据类型(); 这个操作是在创建对象, 此时就会调用构造方法。
在创建对象的时候小括号中我们可以传递一些参数, 程序会根据传递的参数调用对应的构造方法。
构造方法的注意事项:
1. 如果在一个类中我们没有给出构造方法,那么系统会帮我们提供一个空参数的构造方法。
2. 如果在一个类中我们给出了构造方法,那么系统就不会帮我们提供这个空参数的构造方法了。
3. 构造方法支持重载。
JavaBean:
javabean就是Java编写类的规范, 只要一个类符合这些规范,那么这个类就可以称为是一个Javabean。
Javabean规范
1. 将属性私有。
2. 提供get/set方法
3. 提供空参数的构造方法(必须),提供有参数的构造方法(选做)
匿名内部类:
以前都是有具体名字的对象:
Stuent s1 = new Student();
s1就是对象的名字,创建完名字后我们可以反复的使用这个对象名s1反复的来使用这个对象。但有些情况下,为了书写方便,也可以不为“对象”起名字,通过这样创建的对象就是匿名对象,如:new Student();
匿名对象应用的场景:
对于某个类中的某一个方法,只调用一次,当这个方法执行结束后, 该匿名对象会成为垃圾。即:
匿名对象由于没有引用指向,所以在使用过后即变为垃圾,会被垃圾回收器最终回收。
注意:
每个匿名对象都是独立的,互不相关的。比如下面两行代码,第一行的new Person() 和第二行的完全是不同的Person对象。
new Person().setName("张三") //匿名对象name赋值
sout(new Person().getName()); //打印匿名对象的name值为null
2继承(extends)
概念:
将多个对象中相同的属性和行为抽取到一个类中,叫做父类。所有继承父类的类叫做子类,均拥有父类中非私有的属性和行为,可以直接使用。 最终子类与父类的关系为 is a 的关系(如:苹果是水果的一种,人是动物的一种)
继承作用(优缺点):
优点:提高了代码的复用性。即父类中的内容可以在所有子类中使用 子类可以在父类基础上扩展新的功能。
缺点:继承后产生依赖关系,让子类与父类耦合。
Java中继承的特点:
1.java中只能单继承,子类不能同时继承多个父类
2.java中可以多级继承:子类还可以再有子类
3.父类中私有成员可以被子类继承,但没有权限访问(相当于不能被继承)
4.构造方法不存在继承
继承后的构造过程:
1、先父后子:先创建父类的对象空间(父类构造方法先执行); 再创建子类的对象(子类 构造方法再执行)
2、 默认在每个子类构造方法中的第一行均有一个不显示的super(),用于调用父类的空参构造。
通常情况下:子类要参考父类,来定义相同形式的构造方法。
关于继承的一道经典例题:
public class TestMethod {
public static void main(String[] args) {
Zi zi = new Zi();
zi.method2();
}
}
abstract class Fu{
// public abstract void method();
public void method() {
System.out.println("你好,我是父");
}
public void method2() {
// method();
// this.method();
Fu.this.method();
}
}
class Zi extends Fu {
@Override
public void method() {
System.out.println("你好,我是子");
}
}
此题可以看出:
重写(Override)
子类中可以访问父类非私有的成员方法(继承后子类拥有和父类一模一样的方法)
子类可以根据自身需求重写(在子类中手动显式定义出一个与父类完全相同方法声明的方法) 会出现@Override注解,表示该方法是在重写父类的方法。用于语法上确保是一个正确的重写方法。
子类重写方法的语法规则:
1.返回值类型、方法名、参数列表必须与父类被重写方法相同。
2.访问权限>=父类被重写方法:
public > protected > 默认不写 > private(实际已不涉及方法重写)
关键字(this、super)
this: 代表当前对象的引用
this.变量 访问本类的成员变量(通常用于区分成员变量与局部变量)
this.方法(参数) 访问本类的成员方法
this(参数) 访问本类其他参数构造方法(必须在构造方法的第一行)
super:代表当前对象的父类对象空间
super.变量 : 访问父类的成员变量(通常用于区分成员变量与局部变量)
super.方法(参数) : 访问父类的成员方法
super(参数) : 访问父类构造方法(必须在构造方法的第一行)
this、super访问不同的成员:
1、访问变量:
变量: 局部变量 ; this.变量 : 本类变量; super.变量 : 父类变量
注意:在子类中访问变量:如果没有强调this与super,则访问优先级 局部变量>本类成员变量>父类成员变量
2、访问方法:
this.方法 : 本类方法
super.方法 : 父类方法注意: 在子类中调用方法:如果没有强调this与super,则访问优先级 本类方法>父类方法
3、 访问构造方法:
this(参数) : 调用本类其他参数构造
super(参数) : 调用父类构造注意: 在子类中调用其他构造方法:
每个构造默认第一行有一个隐式的super()调用父类的空参构造。 只能出现一个this或者super,不能同时出现。 必须出现一个this或者super。 如果给定了this或者super,则不再拥有隐式的super()调用父类的空参构造。
抽象(abstract)
抽象类:
thinking in java:具有抽象方法的类是抽象类, 抽象类一定是为子类而设计定义,为了给子类定义共性内容
注意: 抽象类不能创建对象。 抽象类的定义,限定了子类必须实现的方法
抽象类:public abstract class 类名
抽象方法:public abstract void 方法名(参数); 没有方法体
注意:当子类继承具有抽象方法的类后,必须实现抽象方法或者将自己设置成抽象方法 。 抽象类可以有非抽象方法,也可以可以没有抽象方法。
思考:抽象类具有构造方法么? 抽象类不能创建对象,为什么要有构造方法?
答案:抽象类一切是为了子类服务,虽然抽象类不能创建对象,但是子类用自己的构造方法通过super来调用父类的构造方法,进而给自己的变量赋值。
关键字修饰符:final
一个修饰符可以修饰的四个位置:
1).类:表示"最终类"——此类不能被"继承",例如:String类——里面的方法不希望被改写,也不希望被扩展public final class String{ }
2).成员属性:表示"最终方法"——此方法不能被"重写"。
3).成员方法:常量,其值/引用不可以被更改。
4).局部变量:常量,其值/引用不可以被更改。不要忽视方法参数也属于成员变量的一种。简单总结:
修饰方法:表明该方法是最终方法,不能被重写
修饰变量:表明该变量是常量,不能再次被赋值
修饰类:表明该类是最终类,不能被继承
注意:构造方法(final不可以修饰)
关键字(static)
static关键字:静态关键字,定义属于类空间的内容,被所有对象共享使用。
被static修饰的内容可以通过类名直接访问【建议】,也可以通过对象名访问。不属于任何一个对象
注意:静态内容在方法区的静态存储区存储 。 静态内容永远比非静态内容先加载到内存
1).修饰"成员变量":静态变量
常用与final连用修饰静态常量
public static final 数据类型 变量名 = 值;
2).修饰"成员方法":静态方法
静态方法只能访问静态成员
思考:为什么?答:注意事项
3).修饰"代码块":静态代码块——用于初始化"静态成员变量"
静态代码块会在第一次使用类时执行
接口(interface)
1). interface定义:
public interface Method{//接口 定义格式,接口名字叫做Method
public abstract void method1();//接口的抽象方法,没有方法体,其中public abstract 可以默认不写,但是是abstract修饰的,子类继承后必须重写该方法
default void method2(){//接口的默认方法,子类通过继承实现接口后,直接子类名称.method2() 可以直接调用,根据子类自身需求来看重不重写。相当于抽象类中的普通方法。
代码块
}
public void method3(){//本身普通的方法
}
}
2).接口的作用:弥补了Java单继承的弊端,可以使一个子类在继承其它类的同时,实现一个或多个接口; 3).子类实现接口使用关键字:implements 4).子类实现接口后,必须重写接口中定义的抽象方法。
注意:
1.公有、静态方法【较常用,有方法体】——不能被子类继承(抽象类/普通父类中的静态方法是可以被继承的)
2).接口中没有构造方法!不能创建对象。
3).接口中的"静态方法"只属于接口,不能被子类继承,只能通过"接口名.静态方法名()“方式访问!
4).JDK8的接口中没有"私有成员”。JDK9以后,接口有新的改动,现在应用不多。
5).接口中的public、static、final等均可以省略
子类可以: 1).继承一个类的同时实现一个或者多个接口; 2).也可以直接实现一个或多个接口 3).接口可以多继承接口
小结: 1).类和类:继承关系,extends关键字,单继承; 2).类和接口:实现关系,implements关键字,多继承 3).接口和接口:继承关系,extends关键字,多继承
03多态
多态的概念:一类事物的多种表现形态
1.代码体现:父类类型 变量名 = new 子类类型(); (父类引用指向子类对象!!!!!)
2.意义体现:子类重写父类方法,子类对象的多种表现形态
3.多态的使用前提:必须要有继承/实现关系
4.多态时左边是"父级"的就可以:父类/抽象类/接口、爷爷类/抽象类/接口…
5. 多态时右边是"子级"的就可以:子类、孙类…
多态的弊端:子类对象在多态时,只能访问父类(中定义的)成员,不能访问子类特有成员。除非子类重写父类的方法,访问的是子类重写后的方法。
多态的好处:利于程序扩展。
多态的三种形式:
1).父级普通类 变量名 = new 子类();
2).父抽象类 变量名 = new 子类();
3).父接口 变量名 = new 子类();
2.多态的三种使用方式:
1).变量的多态【不常用:访问受限制】
父类/父抽象类/父接口 变量名 = new 子类();
Animal a = new Cat();
2).方法形参的多态【最常用】
public static void print(Animal animal) {
}
3).返回值的多态【较常用】
public static Animal getAnimal(){
//return new Cat();
return new Dog();
}
多态的转型:
1).向上转型(多态本身就是向上转型):
Animal a = new Cat();
缺点:不能访问子类特有成员2).向下转型:
instanceof关键字:用于判断某个对象是否属于某个类型
对象 instanceof 类型 →→→→得到布尔值如果a指向的对象是子类对象,而使用的是多态父类形式,则可以重新转回子类类型,进而调用子类特有方法 if(a instanceof Cat){ Cat c = (Cat)a; c.特有成员方法(); }
内部类(嵌套类):定义在一个类内部的类
有两种内部类:
A).成员内部类:定义在一个类的成员位置的。
成员内部类对象需要有外部类对象
可以在第三个类中创建。
格式:外部类.内部类 变量名 = 外部类对象.new 内部类();
B).局部内部类:定义在一个方法的内部的。
不可以在第三个类中创建,只能在外部类的方法中创建
内部类也会被编译成一个class文件
内部类表示一种所属关系
内部类可以访问外部类成员
匿名内部类:
匿名局部内部类:它是"局部内部类"的一种,也是定义在方法中的。
它的编写,必须要有一个外部的父类或者父接口。匿名内部类的操作: 定义了一个匿名子类的同时,创建了该子类的对象。 重写方法的过程就是定义匿名子类的过程。 匿名内部类的最终表现:创建了指定类的子类对象。 格式:使用多态接收匿名内部类对象 父类/接口 变量 = new 父类/接口() { 重写方法 } 变量.方法() →→→→ 调用的是匿名子类重写后的方法
优点: 省了单独定义一个类,简化了书写
缺点: 1.编写麻烦 2.可读性差 3.通常使用匿名对象,所以通常不能重用,只能在调用这个方法时使用