面向对象
一、概念:
所谓面向对象是一种编程思想,通过这种思想可以吧生活中的复杂事情变的简单化,从原来的执行者变成指挥者,面向对象是基于面向过程而言的,面对对象强调结果,比如你要去上学,强调的是去学校,这个动作就是面向对象,而面向过程强调过程,强调的是你去学校的过程,比如骑自行车骑啊骑啊的去。
二、类与对象
- 定义
所谓类,就是将具有相似的行为或者属性的事物抽象或者集合形成一个类,就如动物类,人类,植物类
所谓对象,通常表现为实体,是类的具体实例,万物皆对象,比如动物类有猫狗这些等等 - 类与对象的关系
对象是类的实例,类是对象的模板 - 生活中的类与对象
计算机语言是用来描述现实世界事物的。属性+行为,那怎么通过java语言描述呢?通过类来描述事物,把事物的属性当做成员变量,把行为当做成员方法,比如生活中有手机这个事物,手机具有的
- 属性:尺寸,品牌,价格,颜色
- 方法:打电话,发短信,听音乐
- 类:手机类,抽取属性和行为
- 对象:iPhone手机啊,华为手机啊,小米手机啊
- 类与对象的创建和使用
通过class关键字创建类,通过new关键字创建对象。
public class Test1 {
public static void main(String[] args) {
//p是引用对象,持有了对于Person对象的地址值的引用
//此时的p,含有属性,但都是默认值
Person p = new Person();
//设置属性值
p.name="lisi";
p.age=20;
//调用方法
p.eat();
p.sleep();
}
}
class Person{
//属性--成员变量
String name;
int age;
//行为--方法
void eat(){
System.out.println("吃饭饭");
}
void sleep(){
System.out.println("睡觉觉");
}
}
三、类与对象在内存中的存储
java内存分为5大块,推,虚拟机栈,本地方法栈,方法区,程序计数器,我们基础阶段主要学习栈,推
- 一般来讲局部变量存在栈中,方法执行完毕内存就被释放
- 对象(new出来的东西)存在堆中,对象不再被使用时,内存才会被释放
- 每个堆内存的元素都有地址值
- 对象中的属性都是有默认值的
- 在栈内存中,创建一个引用变量p,持有对象的地址值
- 在堆内存中,创建Person对象,并且开辟变量的空间,完成初始化
- 给堆内存中的元素,分配一个唯一标志,地址值。交给p去保存。
- p.name=”lisi”;p.age=20;就去堆内存中找唯一的地址值,找到Person对象,并对其属性进行修改赋值。
- p.eat();就去堆内存中找唯一的地址值,找到Person对象,执行Person对象的方法。
四、封装——面向对象的三大特征之一
封装是指隐藏对象的属性和实现细节,由private关键字修饰,当一个类的属性或者方法不想让其他类访问时,可以用private修饰,仅仅对外提供公共的访问方式。由set(),get()方法提供,封装的好处是:
- 提高安全性
- 提高重用性
class Person{
//成员属性
private int age;
private String name;
//成员方法
void eat(){
System.out.println("吃饭");
}
void sleep(){
System.out.println("睡觉");
}
private void work() {
System.out.println("上班");
}
}
public class Text_private {
public static void main(String[] args) {
//在测试类里创建Perso对象
Person person = new Person();
//person.age = 18;//报错,private修饰不能使用
//person.work();
person.eat();
person.sleep();
}
}
运行结果
**解决方法:**对外提供set(),get()方法 在eclipse中,位于source栏下面的Getters and Setters,自动生成设置和获取属性的方法
class Person{
//成员属性
private int age;
private String name;
//获取属性的方法
public int getAge() {
return age;
}
//设置属性的方法
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
//成员方法
void eat(){
System.out.println("吃饭");
}
void sleep(){
System.out.println("睡觉");
}
private void work() {
System.out.println("上班");
}
}
public class Text_private {
public static void main(String[] args) {
//在测试类里创建Perso对象
Person person = new Person();
person.setAge(18);
person.setName("迪丽热巴");
System.out.println(person.getAge());
System.out.println(person.getName());
person.eat();
person.sleep();
}
}
运行结果
五、构造方法
-
定义
构造方法也叫构造函数,构造器,构造方法是一种特殊的方法,它是一个与类同名且没有返回值类型的方法。对象的创建就是通过构造方法来完成,其功能主要是完成对象的创建或者对象的初始化。当类实例化一个对象时会自动调用构造方法。构造方法和其他方法一样也可以重载,构造方法可以自己定义也可以使用系统提供的默认构造方法。 -
形式
可以无参也可以有参修饰符 类名(【参数】) { 代码…… }
-
练习
- 构造方法创建对象
- 构造方法对对象初始化
class Person{
//成员属性
private int age;
private String name;
//无参构造方法
Person(){}
//有参构造方法
Person(int age,String name){
this.age = age;
this.name = name;
}
@Override
public String toString() {
return "Person [age=" + age + ", name=" + name + "]";
}
}
public class Text_private {
public static void main(String[] args) {
//在测试类里创建Perso对象
//创建一个匿名对象(没有名字的对象)
new Person();
//创建Person对象
Person person = new Person();
//创建Person对象并对属性初始化
Person person1 = new Person(18,"迪丽热巴");
//将对象以字符串输出
System.out.println(person1.toString());
}
}
运行结果
六、构造代码块和局部代码块
1. 构造代码块
(1)在类的内部,方法的外部,的代码块 {}
(2) 通常用于抽取构造方法中的共性代码
(3) 每次调用构造方法前都会调用构造代码块,优先于构造方法执行
public class Text2 {
String country;
//构造代码块
{
country = "中国";
}
//构造方法
Text2(){
System.out.println("1号选手来自"+country);
}
Text2(int a){
System.out.println(a+"号选手来自"+country);
}
public static void main(String[] args) {
Text2 t1 = new Text2();
Text2 t2 = new Text2(2);
}
}
运行结果
由结果可知,先是构造代码块先执行,将country变量赋值,然后在创建对象时构造方法执行使用到country变量
2.局部代码块
1、 在方法里面的代码块
2、 通常用于控制变量的作用范围,出了括号就失效
3、 变量的范围越小越好,成员变量会有线程安全问题
4、 总结:执行顺序:
构造代码块是最优先的,局部代码块顺序执行
public class Text2 {
{
System.out.println("构造代码块");
}
Text2(){
System.out.println("构造方法");
}
void method() {
{System.out.println("局部代码块");}
}
public static void main(String[] args) {
new Text2().method();
}
}
运行结果
七、this关键字
- this表示当前对象的引用,比如引用当前对象的成员变量,成员方法
- this可以防止成员变量与局部变量名字的冲突,当传入参数和成员变量名一样时可以使用this关键字区分
- 在构造函数中,this()必须在第一行,表示使用自身的构造方法,根据参数来匹配调用的构造函数
//测试this关键字
public class Text_this {
String name;
int age;
//参数名和成员变量一样,引用this关键字区别
public String toString(String name,int age) {
this.name = name;//this.name表示使用成员变量,并将参数赋值给它
this.age = age;//如果不用this区分,根据变量使用的就近原则,则使用到的是局部变量
return "姓名"+ this.name +",年龄"+ this.age;
}
Text_this(){
this("赵丽颖",18);//调用自身的有参构造方法,并且只能出现在第一行
}
//有参构造方法
Text_this(String str,int age){
System.out.println("姓名"+str+",年龄"+age);
}
public static void main(String[] args) {
System.out.println(new Text_this().toString("迪丽热巴", 18));
}
}
运行结果
八、继承
1.概念
继承是面向对象最显著的一个特性。继承是从已有的类中派生出新的类(子类),子类能继承已有类的数据属性和行为,并能扩展新的能力。
Java继承是使用已存在的类的定义作为基础建立新类的技术,新类的定义可以增加新的数据或新的功能,也可以用父类的功能,但不能选择性地继承父类/超类/基类,只能继承一个父类,Java只支持单继承。
这种技术使得复用以前的代码非常容易,能够大大缩短开发周期,降低开发费用。提高复用性:只要继承父类,就能有一样的功能
2.特点
- 使用extends关键字
- 相当于子类把父类的功能复制了一份
- java只支持单继承
- 继承可以传递(爷爷,儿子,孙子的关系)
- 不能继承父类的私有成员
- 继承多用于功能的修改,子类可以拥有父类的功能的同时,进行功能拓展
语法: class A extends B { }
//父类
class Parent{
int age;
String name;
void eat() {
System.out.println("吃饭");
}
void sleep() {
System.out.println("睡觉");
}
}
//子类
class Son extends Parent{
//子类可以拥有从父类继承到的属性和方法
}
public class Text {
public static void main(String[] args) {
//创建子类对象
Son son = new Son();
//访问从父类继承的属性和方法
son.age = 18;
son.name = "张三";
System.out.println(son.age +" " + son.name);
son.eat();
son.sleep();
}
}
运行结果
3.super关键字
- super表示父类的一个引用对象,通过super关键字可以使用父类的内容,如super.name,访问父类的成员变量
- 如果用super(),必须出现在调用位置的第一行,表示使用父类的无参构造
- 子类创建对象时,父类的无参构造方法也会运行,因为在子类的构造方法中,有一个默认的隐式super()语句
- 子类使用super()调用父类的构造方法时,必须在子类的构造方法中使用,并且只能使用一次
class Fu{
int age;
String name;
public Fu() {
System.out.println("父类的无参构造方法");
}
Fu(int age,String name){
this.age = age;
this.name = name;
System.out.println("父类的有参构造方法");
}
}
class Zi extends Fu{
Zi(){
super(18,"父");
//super();//注:不能同时调用父类的几个构造方法
//访问父类的属性
System.out.println(super.age);
System.out.println(super.name);
}
}
public class Text_super {
public static void main(String[] args) {
new Zi();
}
}
九、static关键字
- 作用范围:可以修饰成员变量,成员方法,使用static修饰后属于类资源,而不再属于对象,随着类的加载而加载
- 特点:只加载一次,随着类的加载类的消失而消失,静态资源只能访问静态资源不能访问非静态资源,非静态资源既可以访问静态资源,又可以访问静态资源,static不能和this,super关键字一起使用,因为类存在时对象可能还没创建,并且static资源优先于对象存在
- 静态代码块:static修饰的代码块称为静态代码块
- 调用:可以直接使用类名调用,在本类中使用静态资源可以省略类名
public class Text_static {
int age;
static String country = "中国";//静态资源——类变量
public static void main(String[] args) {
method();
Text_static.method1();
}
private static void method1() {
System.out.println("静态方法");
}
//静态资源——静态方法
private static void method() {
System.out.println("来自"+country);
//System.out.println(age);静态不能访问非静态
}
}
运行结果
静态代码块,构造代码块,构造方法,局部代码块,静态方法的执行顺序
1、 静态代码块:在类加载时就加载,并且只被加载一次,一般用于项目的初始化
2、 构造代码块:在调用构造方法前会自动调用,每次创建对象都会被调用
3、 局部代码块:方法里的代码块,方法被调用时才会执行
4、 静态代码块:static{ },位置:在类里方法外
public class Text {
public static void main(String[] args) {
new Text_staticSequence().method();
System.out.println("_________________");
new Text_staticSequence().method1();
}
}
class Text_staticSequence {
//构造代码块
{
System.out.println("构造代码块");
}
//构造方法
public Text_staticSequence() {
System.out.println("构造方法");
}
//静态方法
public static void method() {
System.out.println("静态方法");
}
//静态代码块
static {
System.out.println("静态代码块");
}
//普通方法
void method1(){
System.out.println("普通方法");
//局部代码块
{
System.out.println("局部代码块");
}
}
}
运行结果
由运行结果可以得出
- 执行顺序为:静态代码块>构造代码块>构造方法>静态方法/局部代码块
- 测试中,创建了两次对象,但是静态代码块只执行一次,构造代码块与构造方法随着创建对象而运行
- 静态方法与局部代码块需要对象调用,所以最后才运行
使用static关键字
- static可以修饰类(最终类),但是不能被继承
- static可以修饰变量(常量),但是值不能被修改
- static可以修饰方法(最终方法),但是不能被重写
十、多态
- 概述
多态,通常描述的是对象,即对象的不同状态 比如猫既有猫类自己的状态,又有动物类的状态,主要是指同一个对象,在不同时刻,代表的对象不一样,指的是对象的多种形态。 - 对象构成多态的条件
- 必须要发生继承关系
- 必须存在方法的覆盖
- 必须有父类引用指向子类对象
- 多态的特点
- 编译看左边,运行看右边
说明:即只能使用父类提供的方法,不能使用子类特有的方法,否则不能通过,运行时看右边,即看new的对象,如Animal a = new Cat();则使用的是Cat里面的方法 - 多态使用的成员变量是父类的成员变量
- 多态里的静态方法不能被重写
/**
* 多态:
* 前提:继承关系,方法重写
* 口诀:父类引用 指向 子类对象(向上转型)
* @author TEDU
*/
public class Text1 {
public static void main(String[] args) {
Animal a = new Cat();//编译看左边,运行看右边,
//只能使用父类提供的,运行时看new的对象,
//即不能使用子类特有的方法
a.eat();
a.sleep();
a.catchFood();
System.out.println(a.age+a.name);//多态使用的是父类成员
a.show();//静态方法不可以重写
}
}
class Animal{
int age;
String name;
Animal(){
this.age = 18;
this.name = "动物";
}
public void eat() {
System.out.println("吃饭");
}
public void sleep() {
System.out.println("睡觉");
}
public void catchFood() {
System.out.println("捕食");
}
public static void show() {
System.out.println(1);
}
}
class Cat extends Animal{
public void eat() {
System.out.println("猫吃鱼");
}
public void sleep() {
System.out.println("猫睡觉");
}
public static void show() {
System.out.println(2);
}
}
十一、抽象类
- 抽象方法
当不需要强调方法的具体实现细节,或者方法中没有具体实现意义,如动物类里面有个吃饭的方法,但是又不知道具体实现,可以将方法定义为抽象方法,抽象方法没有方法体,其具体实现由子类去重写。 - 抽象类
由abstract关键字修饰的类叫抽象类,抽象方法只能存在于抽象类中,抽象类中既有抽象方法,也可以有普通方法。 - 抽象类与抽象方法的特点
- 抽象类不可以创建对象(不能别实例化),由子类继承抽象类去实现抽象类里的方法
- 抽象类有构造方法,但是不可以创建对象,主要为子类提供多态功能
- 抽象方法没有方法体,并且只能存在于抽象类中
- 继承抽象类的类必须要重写抽象类里的所有抽象方法
package cn.tedu.day09;
public class Text2 {
public static void main(String[] args) {
//Animal an = new Animal();错误,抽象类不能实例化
Animal cat = new Cat();//多态
cat.catchFood();
cat.eat();
cat.sleep();
}
}
//抽象类
abstract class Animal{
//构造方法
Animal(){
System.out.println("动物类祖先");
}
//抽象方法
public abstract void eat() ;
public abstract void catchFood();
//非抽象方法
public void sleep() {
System.out.println("冬眠");
}
}
//非抽象类
class Cat extends Animal{
@Override
public void eat() {
System.out.println("猫吃鱼");
}
@Override
public void catchFood() {
System.out.println("猫捉老鼠");
}
}
小练习
模拟老师教书,要求使用抽象类,有教基础的和教框架的老师
package cn.tedu.day09;
public class Text4 {
public static void main(String[] args) {
//javase老师
Teacher t1 = new Teacher1();
t1.setAge(20);
t1.setName("渣渣");
System.out.println(t1.getAge()+t1.getName());
t1.teach();
//javaee老师
Teacher t2 = new Teacher2();
t2.setAge(28);
t2.setName("大牛");
System.out.println(t2.getAge()+t2.getName());
t2.teach();
}
}
//老师类
abstract class Teacher{
private String name;
private int 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;
}
abstract void teach();//教书方法
}
//javase老师
class Teacher1 extends Teacher{
@Override
void teach() {
System.out.println("教java基础");
}
}
//javaee老师
class Teacher2 extends Teacher{
@Override
void teach() {
System.out.println("教java框架");
}
}
十二、接口
-
概述
Java里面由于不允许多重继承,所以如果要实现多个类的功能,则可以通过实现多个接口来实现。Java接口和Java抽象类代表的就是抽象类型,就是需要提出的抽象层的具体表现。OOP面向对象的编程,如果要提高程序的复用率,增加程序的可维护性,可扩展性,就必须是面向接口的编程,面向抽象的编程,正确地使用接口、抽象类这些太有用的抽象类型做为java结构层次上的顶层。 -
特点
-
接口中都是抽象方法,不存在其他方法
-
通过interface关键字创建接口
-
通过implements让子类来实现
-
可以理解成,接口是一个特殊的抽象类
-
接口可以支持多继承,多实现
-
接口和类之间可以多实现,接口和接口之间可以多继承
-
接口是对外暴露的规则,是一套开发规范
-
接口提高了程序的功能扩展,降低了耦合性
入门案例
public class T {
public static void main(String[] args) {
Zi z = new Zi();
z.study();
z.teach();
}
}
interface Fu{
public abstract void study();
public abstract void teach();
}
//实现+重写
class Zi implements Fu{
public void study(){
System.out.println("Zi..study()");
}
public void teach(){
System.out.println("Zi..teach()");
}
}
- 接口的用法
接口没有构造方法,在创建实现类的对象时默认的super(),是调用的默认Object的无参构造。
接口里没有成员变量,都是常量。所以,你定义一个变量没有写修饰符时,默认会加上: public final static
接口里的方法,默认就都是抽象的,如果你不写明是abstract的,那会自动补齐
package cn.tedu.day10;
public class Text_inteface {
public static void main(String[] args) {
Cla cla = new Cla();
//接口的好处:突破单继承的局限,提高程序的功能扩展
cla.open();
cla.opening();
cla.close();
cla.closing();
}
}
interface Interface1{
public abstract void open();
public abstract void opening();
}
interface Interface2{
public abstract void close();
}
abstract class Abs implements Interface1{
public abstract void open();
//当一个类是抽象类时,去实现一个接口就可以不用全部重写里面的抽象方法
}
interface Interface3 extends Interface1,Interface2{
//接口可以多继承
public abstract void closing();
}
class Cla implements Interface1,Interface2,Interface3{
//类可以多实现几个接口,但是要全部重写接口里的抽象方法
@Override
public void closing() {
// TODO Auto-generated method stub
System.out.println("正在关闭");
}
@Override
public void close() {
// TODO Auto-generated method stub
System.out.println("关闭");
}
@Override
public void open() {
// TODO Auto-generated method stub
System.out.println("打开");
}
@Override
public void opening() {
// TODO Auto-generated method stub
System.out.println("正在打开");
}
}
- 接口总结
- 类与类的关系:继承
- 类与接口的关系:实现
- 接口与接口的关系:继承
说明:类与类之间的继承是单继承,接口与接口之间的继承可以是单继承,也可以是多继承,类与接口间只有实现关系,但是类也可以先继承后再实现某个接口,如class A extends B implements C,D{ //A是类,B也是类,C和D是接口,需要注意的是,实现接口后需要重写所有接口里的抽象方法,除非这个类被abstract修饰成为抽象类。
十三、接口与抽象类的区别
- 相同点:
- 都是用来设计抽象层,是程旭设计的结果
- 都不能实例化
- 不同点
- 接口很灵活,可以被实现类多实现,可以和接口发生多继承
- 抽象类只能被子类单继承
- 接口体现了程序间的松耦合,抽象类体现了前耦合
- 抽象类里面有构造方法,给子类提供多态,接口里面没有构造方法
- 抽象类里有变量也有常量,接口里只有常量,并且可以简写
- 抽象类里有普通方法和抽象方法,接口里只有抽象方法