面向对象

面向对象:以类的方式组织代码,以对象组织数据

特性:

  1. 封装
  2. 继承
  3. 多态

类:抽象概念

对象:具体事物

  • 面向对象是java学习的重中之重,毕竟java就是一个面向对象的语言~
  • 类 = 属性+方法
  • 面向对象的概念适合复杂系统、多人协作
  • 从宏观上来说,java是面向对象的,但在微观上是面向过程的

创建

对象的创建

使用new实例化一个对象,如

Student student = new Student();//实例化对象

new时:

  • 内存空间的分配
  • 属性的初始化
  • 构造器的调用
  • 返回一个对象的引用(指针)

构造器

构造器在实例化时首先被自动调用,用于初始化参数。

new的本质是调用了构造器,返回一个对象

  • 名字和类名相同

  • 没有返回类型(不能写!)

  • 可以传参

  • this是一个指针,指向这个对象本身

    public class Person {
    String name;
    public Person(){
    //构造器
    this.name = "小明";
    } }

封装--访问控制

“高耦合,低内聚”,内部数据操作细节自己完成,不由外部干涉, 暴露少部分方法给外部使用。

封装:禁止访问对象的实际表示,而应该通过接口来访问。

修饰词:

  • public:可以由外部调用,公开使用
  • private:不可由外部调用
  • protected:由本包内或不同包的子类调用


继承

使用extend关键字,表示子类是父类的扩展

public class Student extends Person{
Student(String name){
this.name = name;
}
}
  • 子类拥有父类的全部public/protected方法和属性
  • 且子类可以对所有方法和属性重写
  • private属性无法被继承
  • java中所有类都是object类的子类

构造器

使用super可以访问到父类,构造器中super.generator()可以调用父类的构造器。

public class Person {
String name; public Person(String name){
//构造器
this.name = name;
} }
public class Student extends Person{
Student(String name){
super(name);
}
}
public class Demo2 {

    public static void main(String[] args){
Student s = new Student("小明");
System.out.println(s.name);
}
}

输出“小明”。

如果在子类中不指定调用super,会自动调用

public class Person {
String name;
public Person() {
//构造器
System.out.println("父类Person无参数构造器执行");
}
}
public class Student extends Person{
Student(){
System.out.println("子类Student无参数构造器执行");
}
}

在new Student时输出:

若将子类构造器改为有参,仍然会首先调用父类的无参构造器

大致逻辑如下:

注:

  • 调用构造器时,需要将父类构造器调用语句放在子类构造器的第一句
  • 父类没写无参,默认有一个空的构造器函数
  • 如果写了一个有参构造器,那么父类就没有无参构造器了,子类不能自动调用构造器,即子类中必须显式调用有参构造器了。

方法重写

  1. Person类:
public static void test(){
System.out.println("Person Test");
}

Student类:

public static void test(){
System.out.println("Student Test");
}

调用:

public static void main(String[] args){
Student s = new Student("小明");
s.test();
}

结果:

  1. 但是,如果修改main
public static void main(String[] args){
Person s = new Student("小明");
s.test();
}

会导致输出:

这可以说明

  • 调用的方法根据声明的类型确定
  1. 以上结论来自于静态方法

    如果全部改为非静态,即将test改为无static修饰

     @Override
    public void test(){
    System.out.println("Student Test");
    }

注意点:

  • override 的前提是继承
  • 方法名相同
  • 参数列表相同(不是重载)
  • 修饰符的范围只能扩大不能缩小 public>protected>default>private
  • 异常的范围可以被缩小但不能扩大,如:ClassNotFoundException->Exception

多态

定义

同一方法根据对象的不同采用不同的行为

引用类型

一个对象的实际类型是确定的,但引用类型并不一致

Student s = new Student();
Person s1 = new Student();
Object s2 = new Student();

实际类型都是Student,而引用类型可以是其任意父类

对于这样的对象s1/s2,如果没有static修饰,调用一个方法时

  1. 若子类父类都有该方法,且子类未重写:调用父类的方法

  2. 若都有,但子类重写了:调用子类的方法

  3. 若只有子类有,则无法调用(需要强制类型转换修改引用类型)

    如在Student写一个新的eat方法:

即能调用的方法取决于其引用类型而不是实际类型

方法修饰

  1. static 属于类,不属于对象,不可重写

  2. final 无法修改,不可重写

  3. private 只属于父类,无法重写

instanceof操作符

语法:

obj instanceof class
System.out.println(s instanceof Student);//true
System.out.println(s1 instanceof Student);//true
System.out.println(s1 instanceof Object);//true
System.out.println(s2 instanceof Student);//true
System.out.println(s2 instanceof Teacher);//false

如果对象的类是class或class的子类,则为True

在编译状态中,class可以是object对象的父类,自身类,子类。在这三种情况下Java编译时不会报错。(需要在同一条继承链上)

在运行转态中,class可以是object对象的父类,自身类,不能是子类。在前两种情况下result的结果为true,最后一种为false。但是class为子类时编译不会报错。运行结果为false。

编译的时候查看其引用类型判断是否报错。

运行的时候查看其实际类型判断是否为true。

强制类型转换

优先级:父类>子类。

子类转父类自动转换。

父类转子类需要强制转换。

转父类后部分方法可能无法再调用。


static

  • static修饰(静态)的从属于类,普通的从属于对象

  • 静态方法不能调用非静态成员

变量

静态变量(类变量)

  • 有static修饰的变量为静态变量,在该类的内存中只能存在一个,可以使用类名.变量名进行访问
  • 内部任何方法都可以直接访问静态变量(可以不使用类名.静态成员进行访问)
  • 类外部可以使用类名访问类中静态变量

实例变量

  • 无static修饰的变量

  • 每创建一个实例就会生成一个新的内存空间

  • 类内部只有非静态方法可以访问实例变量

  • 静态方法或其他类中只能通过实例对象访问

静态变量的作用

  • 静态变量被所有实例共享,可以作为实例对象间的共享数据
  • 如果所有实例都有一个相同的常量属性,可以定义为static以节省空间

方法

静态方法(类方法)

  • 静态方法不需要通过任何实例就可以被调用,
  • 不能使用this/super关键字
  • 也不能直接访问类内部的实例变量和实力方法
  • 可以直接调用类内部的静态变量和静态方法

实例方法

  • 通过实例对象访问

代码块

静态代码块

  • static{}代码块
  • 用于初始化类(一次性的),为类的静态变量赋初值
  • 类似于一个方法,但不在方法体中
  • 可以在类的任意位置,可以有任意多个
  • java虚拟机在加载类的时候执行静态代码块
  • 多个代码块按顺序运行
  • 静态代码块和静态方法类似,不能访问非静态成员

非静态代码块

  • {}
  • 创建对象时自动执行,不创建对象不执行
  • 代码域中的变量都是局部的,只在内部使用

抽象

abstract修饰

抽象类

  • abstract修饰的方法
  • 抽象类中可以有抽象方法和具体方法
  • 抽象类无法实例化

抽象方法

  • 抽象方法只声明没有方法体
  • 抽象方法必须在抽象类中
  • 子类重写父类时,必须重写父类的所有抽象方法
  • 不能用private修饰,因为private阻止重写

实例

public abstract class Shape {
public int width; // 几何图形的长
public int height; // 几何图形的宽 public Shape(int width, int height) {
this.width = width;
this.height = height;
} public abstract double area(); // 定义抽象方法,计算面积
}
public class Square extends Shape {
public Square(int width, int height) {
super(width, height);
} // 重写父类中的抽象方法,实现计算正方形面积的功能
@Override
public double area() {
return width * height;
}
}
public class Triangle extends Shape {
public Triangle(int width, int height) {
super(width, height);
} // 重写父类中的抽象方法,实现计算三角形面积的功能
@Override
public double area() {
return 0.5 * width * height;
}
}

接口

  • 普通类:只有具体实现
  • 抽象类:有具体实现和规范(抽象方法)
  • 接口:只有规范,没有具体实现 专业的约束,实现约束和实现的分离,比抽象类更加抽象

接口定义

[public] interface interface_name [extends interface1_name[, interface2_name,…]] {
// 接口体,其中可以包含定义常量和声明方法
[public] [static] [final] type constant_name = value; // 定义常量
[public] [abstract] returnType method_name(parameter_list); // 声明方法
}
  • 接口只能继承接口
  • public定义的接口可以被任何类使用,而没有public只能被包内使用
  • 接口中的变量隐式声明为public static final(可以不写),即为常量,所以全部必须初始化
  • 接口中的方法隐式声明为 public abstract

接口实现

  • 一个类可以实现一个或者多个接口

  • 实现使用implements关键字

    <public> class <class_name> [extends superclass_name] [implements interface1_name[, interface2_name…]] {
    // 主体
    }
  • 与继承类似,可以获得所有的常量和方法

  • implements在extend后

  • 类实现接口后必须重写所有抽象方法

public interface IMath {
public int sum(); // 完成两个数的相加
public int maxNum(int a,int b); // 获取较大的数
}
public class MathClass implements IMath {
private int num1; // 第 1 个操作数
private int num2; // 第 2 个操作数
public MathClass(int num1,int num2) {
// 构造方法
this.num1 = num1;
this.num2 = num2;
}
// 实现接口中的求和方法
public int sum() {
return num1 + num2;
}
// 实现接口中的获取较大数的方法
public int maxNum(int a,int b) {
if(a >= b) {
return a;
} else {
return b;
}
}
}

内部类

类内部定义的类

分类:

  1. 成员内部类
  2. 静态内部类
  3. 局部内部类
  4. 匿名内部类

  • 内部类还是一个独立的类,会编译为独立的.class文件,但前面会冠以类名和$符号
  • 是内部类的一个成员,可以操作到外部类的私有属性
  • 外部类只有两种级别:public和默认
  • 内部类有四种级别:public、protected、private、默认
Outer o = new Outer();
//外部类可直接new
Inner in = new Inner();
//外部类外需要通过外部类来实例化内部类
Outer.Inner inner = o.new Inner();

实例内部类

没有static修饰,也成为非静态内部类,例:

public class Outer {
class Inner {
// 实例内部类
}
}
  • 和实例方法、实例变量相同,在外部类/外部类以外,必须通过外部类的实例创建内部类的实例
  • 实例内部类中可以访问外部类的所有成员(多层嵌套也可)
  • 外部类中不能直接访问内部类的成员,而必须通过内部类的实例访问(不是很懂)
  • 实例内部类中的成员不能使用static修饰,除非同时有final修饰

静态内部类

static修饰的内部类,例:

public class Outer {
static class Inner {
// 静态内部类
}
}
  • 可以通过外部类创建内部类的实例
  • 类中可定义静态成员/实例成员
  • 可直接访问外部类的静态成员,如果要访问外部类的实例成员,则需要通过外部类的实例去访问。

局部内部类

一个方法中定义的类,如:

public class Test {
public void method() {
class Inner {
// 局部内部类
}
}
}
  • 类似局部变量,不用访问控制修饰符和static修饰符修饰
  • 只在方法内可用
  • 不能定义static成员
  • 内部类的内部类也不能用访问控制修饰符和static修饰符
  • 可访问外部类的所有成员
  • 方法中的成员与外部类成员同名,可以使用 .this. 的形式访问外部类中的成员。

匿名内部类

没有类名的内部类,直接使用new来声明,例:

new <类或接口>() {
// 类的主体
};

一般用法:

  • 继承一个类,重写其方法。
  • 实现一个接口(可以是多个),实现其方法。
public class Out {
void show() {
System.out.println("调用 Out 类的 show() 方法");
}
}
public class TestAnonymousInterClass {
// 在这个方法中构造一个匿名内部类
private void show() {
Out anonyInter = new Out() {
// 获取匿名内部类的实例
void show() {
System.out.println("调用匿名类中的 show() 方法");
}
};
anonyInter.show();
}
public static void main(String[] args) {
TestAnonymousInterClass test = new TestAnonymousInterClass();
test.show();
}
}
  • 和局部内部类相同,可访问外部类所有成员。若位于方法中,只能访问方法中final修饰的量
  • 可以使用非静态代码块进行初始化,在父类的构造函数后执行

java基础(六):面向对象的更多相关文章

  1. Java基础-初识面向对象编程(Object-Oriented-Programming)

    Java基础-初识面向对象编程(Object-Oriented-Programming) 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. Java是一门面向对象的程序设计语言.那么什 ...

  2. 黑马程序员——【Java基础】——面向对象(二)异常机制、包(Package)

    ---------- android培训.java培训.期待与您交流! ---------- 一.异常机制 (一)异常概述 1.异常:就是程序在运行时出现不正常情况. 2.异常类:程序在运行时,出现的 ...

  3. Java基础之面向对象以及其他概念

    一.基础知识:1.JVM.JRE和JDK的区别: JVM(Java Virtual Machine):java虚拟机,用于保证java的跨平台的特性. java语言是跨平台,jvm不是跨平台的. JR ...

  4. 黑马程序员——【Java基础】——面向对象(一)概述、类与对象、继承、抽象类、接口、多态、内部类

    ---------- android培训.java培训.期待与您交流! ---------- 一.面向对象概述 1.面向对象:是一个很抽象的概念,它相对面向过程而言,是一种程序设计的思想. 2.面向对 ...

  5. 【Java基础】面向对象下

    面向对象下 这一章主要涉及其他关键字,包括 this.super.static.final.abstract.interface.package.import 等. static 在 Java 类中, ...

  6. 【java基础】面向对象的三大基本特征之-------继承

    面向对象的三大特征:封装,继承,多态 java通过extends关键字来实现继承,而且是单继承,一个子类只可以有一个直接父类,但是父类还可以有父类... java.long.Object是所有类的父类 ...

  7. 再探java基础——对面向对象的理解(1)

    对象 对象是人们要进行研究的任何事物,从最简单的整数到复杂的飞机等均可看作对象,它不仅能表示具体的事物,还能表示抽象的规则.计划或事件.对象具有属性和行为,在程序设计中对象实现了数据和操作的结合,使数 ...

  8. Java基础(6)- 面向对象解析

    java面向对象 对象 知识点 java 的方法参数是按值调用,是参数的一份拷贝 封装 使用private将 属性值/方法 隐藏,外部只能调用 get,set方法/非private 的接口 获取 重载 ...

  9. Java基础总结--面向对象1

    ---面向对象的概念---1.面向过程与面向对象的区别面向过程:是一种思维习惯,解决一个问题的时候靠的是一个个方法调用--核心是动作面向对象:是一种更接近生活中解决问题的思维习惯,解决特定的问题靠对象 ...

  10. java基础(六) switch语句的深入解析

    引言   switch 语句是非常的基础的知识,掌握起来也不难掌握,语法比较简单.但大部分人基本是知其然,不知其所以然.譬如 早期JDK只允许switch的表达式的值 int及int类型以下的基本类型 ...

随机推荐

  1. 系统整理K8S的配置管理实战-建议收藏系列

    目录 一.ConfigMap 1.1.创建 1.1.1.from-file 1.1.2.from-env-file 1.1.3.from-literal 1.1.4.基于yaml文件创建 1.2.Po ...

  2. Git 分支管理策略汇总

    原文链接: Git 分支管理策略 最近,团队新入职了一些小伙伴,在开发过程中,他们问我 Git 分支是如何管理的,以及应该怎么提交代码? 我大概说了一些规则,但仔细想来,好像也并没有形成一个清晰规范的 ...

  3. Git 实战分支版本管理策略 | TBD++ Flow

    ​简介 随着Git的普及,为了更高效地进行团队协作开发,人们通过经验总结研究出了几套适用于各种团队和项目的分支管理策略,上篇文章我们讲解了 Git Flow 代码版本管理策略,它对版本控制较为严格,主 ...

  4. Go语言核心36讲50

    作为拾遗的部分,今天我们来讲讲与Go程序性能分析有关的基础知识. Go语言为程序开发者们提供了丰富的性能分析API,和非常好用的标准工具.这些API主要存在于: runtime/pprof: net/ ...

  5. redis五种数据结构详解

    5.相关介绍和命令 5. redis是单线程+多路io复用技术 多路复用是指使用一个线程来检查多个文件描述符的就绪状态,比如调用select和poll函数,传入多个文件毛舒服,如果有一个文件描述符就绪 ...

  6. bugku web2

    打开全是滑稽.... 直接查看源码(用firefox的F12来查看,其他的会注释掉)可以得到flag(抓包不知道怎么回事抓不到,不然应该也可以看到注释的flag)

  7. MySQL 的 NULL 值是怎么存储的?

    大家好,我是小林. 之前有位读者在面字节的时候,被问到这么个问题: 如果你知道 MySQL 一行记录的存储结构,那么这个问题对你没什么难度. 如果你不知道也没关系,这次我跟大家聊聊 MySQL 一行记 ...

  8. 《浅谈亚 log 数据结构在 OI 中的应用》阅读随笔

    这篇又长长长了! \(8435\to 8375\to 9729\) 早就馋这篇了!终于学了( 压位 Trie 确实很好写啊 但是总感觉使用范围不是很广的样子 似乎是见的题少 原文里都在用 \(\log ...

  9. 【zookeeper】Zookeeper相关概念、重难点(myid)、语法、使用、工具

    1234567890 1请按照我是想额度插入fvtgb6yhn7ujm8ik,9ol.

  10. Map的遍历方式,常用的key-value遍历方式

    在开发过程中经常会遇到 map 的遍历,本文将会介绍四种常用的 key-value 遍历方式 说明: 增强 for 循环遍历 先取出 map 的 keySet,进行遍历,再取出对应 key 的 val ...