Java面向对象详解

一直在使用Java,但是对于Java的面向对象的彻底理解不是很到位,初始化对象时会发生什么,向上转型和向下转型的目的是什么? 所以写下这篇文章.

面向过程 & 面向对象

面向过程的思维模式
面向过程的思维模式是简单的线性思维,思考问题首先陷入第一步做什么、第二步做什么的细节中。这
种思维模式适合处理简单的事情,比如:上厕所。
面向对象的思维模式
面向对象的思维模式说白了就是分类思维模式。思考问题首先会解决问题需要哪些分类,然后对这些分
类进行单独思考。最后,才对某个分类下的细节进行面向过程的思索。
这样就可以形成很好的协作分工。比如:设计师分了 10 个类,然后将 10 个类交给了 10 个人分别进行详细
设计和编码!
显然,面向对象适合处理复杂的问题,适合处理需要多人协作的问题!
OOP 详解
1 、什么是面向对象
Java 的编程语言是面向对象的,采用这种语言进行编程称为面向对象编程 (Object-Oriented
Programming, OOP)
面向对象编程的本质就是:以类的方式组织代码,以对象的组织 ( 封装 ) 数据。
三大特点
封装 (Encapsulation)
封装是面向对象的特征之一,是对象和类概念的主要特性。封装是把过程和数据包围起来,对数据的访
问只能通过指定的方式。
一般设定为private,通过get set方法操作数据
继承 (inheritance)
继承是一种联结类的层次模型,并且允许和支持类的重用,它提供了一种明确表述共性的方法。
新类继承了原始类后 , 新类就继承了原始类的特性,新类称为原始类的派生类 ( 子类 ) ,而原始类称为新
类的基类 ( 父类 )
多态 (polymorphism)
多态性是指允许不同类的对象对同一消息作出响应。
多态性语言具有灵活、抽象、行为共享、代码共享的优势,很好的解决了应用程序函数同名问题。
2 、类与对象的关系
类是一种抽象的数据类型 , 它是对某一类事物整体描述 / 定义 , 但是并不能代表某一个具体的事物 .
对象是抽象概念的具体实例
例如:张三就是人的一个具体实例 , 张三家里的旺财就是狗的一个具体实例。能够体现出特点 , 展现出功能
的是具体的实例 , 而不是一个抽象的概念 .
3 、对象和引用的关系
引用 " 指向 " 对象
使用类类型、数组类型、接口类型声明出的变量 , 都可以指向对象 , 这种变量就是引用类型变量 , 简称引
创建与初始化对象
使用 new 关键字创建对象
使用 new 关键字创建的时候,除了分配内存空间之外,还会给 创建好的对象 进行默认的初始化 以 及对
类中构造器的调用。
1 分配内存空间   同时将实例变量自动初始化复制

2 显示赋值(如果有的话) 

例如 : 显式赋值
private String name = "tom" ;
3 调用构造器
把对象内存地址值赋值给变量。 ( = 号赋值操作 )
构造器
类中的构造器也称为构造方法,是在进行创建对象的时候必须要调用的。并且构造器有以下俩个特点 :
1. 必须和类的名字相同
2. 必须没有返回类型 , 也不能写 void
构造器的作用 :
1. 使用 new 创建对象的时候必须使用类的构造器
2. 构造器中的代码执行后 , 可以给对象中的属性初始化赋值
构造器重载
默认有一个无参构造器,创建了有参构造器,无参自动被覆盖
除了无参构造器之外 , 很多时候我们还会使用有参构造器 , 在创建对象时候可以给属性赋值
内存分析
JAVA 程序运行的内存分析
stack
1. 每个线程私有,不能实现线程间的共享!
2. 局部变量放置于栈中。
3. 栈是由系统自动分配,速度快!栈是一个连续的内存空间!
heap
1. 放置 new 出来的对象!
2. 堆是一个不连续的内存空间,分配灵活,速度慢!
方法区 ( 也是堆 )
1. 被所有线程共享!
2. 用来存放程序中永远是不变或唯一的内容。(类代码信息、静态变量、字符串常量)

 

学习完类与对象终于认识到什么是类,什么是对象了。接下来要看的就是 java 的三大特征:继承、封
装、多态。
封装
在定义一个对象的特性的时候,有必要决定这些特性的可见性,即哪些特性对外部是可见的,哪些特性
用于表示内部状态。
通常,应禁止直接访问一个对象中数据的实际表示,而应通过操作接口来访问,这称为信息隐藏
1 、封装的步骤
1. 使用 private 修饰需要封装的成员变量。
2. 提供一个公开的方法设置或者访问私有的属性
设置 通过 set 方法,命名格式: set 属性名() ; 属性的首字母要大写
访问 通过 get 方法,命名格式: get 属性名() ; 属性的首字母要大写
idea可以通过快捷键生成 构造器和方法
2 、作用和意义
1. 提高程序的安全性,保护数据。
2. 隐藏代码的实现细节
3. 统一用户的调用接口
4. 提高系统的可维护性
5. 便于调用者调用。
良好的封装,便于修改内部代码,提高可维护性。
良好的封装,可进行数据完整性检测,保证数据的有效性
3 、方法重载
类中有多个方法 , 有着相同的方法名 , 但是方法的参数各不相同 , 这种情况被称为方法的重载。方法的重载
可以提供方法调用的灵活性
继承
为什么需要继承?继承的作用?
第一好处:继承的本质在于抽象。类是对对象的抽象,继承是对某一批类的抽象。
第二好处:为了提高代码的复用性。
extands 的意思是 扩展 。子类是父类的扩展
1 、继承
1. 继承是类和类之间的一种关系。除此之外 , 类和类之间的关系还有依赖、组合、聚合等。
2. 继承关系的俩个类,一个为子类 ( 派生类 ), 一个为父类 ( 基类 ) 。子类继承父类 , 使用关键字 extends
表示。
public class student extends Person{ }

子类中继承了父类中的属性和方法后 , 在子类中能不能直接使用这些属性和方法 , 是和这些属性和方法原有
的修饰符 (public protected default private) 相关的。
例如 :
父类中的属性和方法使用 public 修饰 , 在子类中继承后 " 可以直接 " 使用
父类中的属性和方法使用 private 修饰 , 在子类中继承后 " 不可以直接 " 使用
父类中的构造器是不能被子类继承的 , 但是子类的构造器中 , 会隐式的调用父类中的无参构造器 ( 默认使用
super 关键字 )
2 Object
java 中的每一个类都是 " 直接 " 或者 " 间接 " 的继承了 Object . 所以每一个对象都和 Object 类有 "is a" 的关
系。从 API 文档中 , 可以看到任何一个类最上层的父类都是 Object (Object 类本身除外 )AnyClass is a
Object
Object 类中 , 提供了一些方法被子类继承 , 那么就意味着 , java , 任何一个对象都可以调用这些被继承
过来的方法。 ( 因为 Object 是所以类的父类 )
例如 :toString 方法、 equals 方法、 getClass 方法等
:Object 类中的每一个方法之后都会使用到 .
3 Super 关键字
子类继承父类之后 , 在子类中可以使用 this 来表示访问或调用子类中的属性或方法 , 使用 super 就表示访问
或调用父类中的属性和方法
super 使用的注意的地方】
1. super 调用父类构造方法,必须是构造方法中的第一个语句。
2. super 只能出现在子类的方法或者构造方法中。
3. super this 不能够同时调用构造方法。(因为 this 也是在构造方法的第一个语句)
4 、方法重写
方法的重写( override
1. 方法重写只存在于子类和父类 ( 包括直接父类和间接父类 ) 之间。在同一个类中方法只能被重载,不
能被重写 .
2. 静态方法不能重写
1. 父类的静态方法不能被子类重写为非静态方法 // 编译出错
2. 父类的非静态方法不能被子类重写为静态方法; // 编译出错
3. 子类可以定义与父类的静态方法同名的静态方法 ( 但是这个不是覆盖 )
1. 重写的语法
1. 方法名必须相同
2. 参数列表必须相同
3. 访问控制修饰符可以被扩大 , 但是不能被缩小: public protected default private
4. 抛出异常类型的范围可以被缩小 , 但是不能被扩大
ClassNotFoundException ---> Exception
5. 返回类型可以相同 , 也可以不同 , 如果不同的话 , 子类重写后的方法返回类型必须是父类方法返回
类型的子类型
例如 :父类方法的返回类型是 Person, 子类重写后的返回类可以是 Person 也可以是 Person
子类型
1. 总结:
方法重写的时候,必须存在继承关系。
方法重写的时候,方法名和形式参数 必须跟父类是一致的。
方法重写的时候,子类的权限修饰符必须要大于或者等于父类的权限修饰符。 ( private < protected <
public friendly < public )
方法重写的时候,子类的返回值类型必须小于或者等于父类的返回值类型。 ( 子类 < 父类 ) 数据类型没有
明确的上下级关系
方法重写的时候,子类的异常类型要小于或者等于父类的异常类型。
多态
1 、认识多态
多态性是 OOP 中的一个重要特性,主要是用来实现动态联编的,换句话说,就是程序的最终状态只有在
执行过程中才被决定而非在编译期间就决定了。这对于大型系统来说能提高系统的灵活性和扩展性。
多态可以让我们不用关心某个对象到底是什么具体类型,就可以使用该对象的某些方法,从而实现更加
灵活的编程,提高系统的可扩展性。
允许不同类的对象对同一消息做出响应。即同一消息可以根据发送对象的不同而采用多种不同的行为方
式。
相同类域的不同对象 , 调用相同的方法 , 执行结果是不同的
1. 一个对象的实际类型是确定的
例如 : new Student(); new Person();
2. 可以指向对象的引用的类型有很多
Student s1 = new Student ();
Person s2 = new Student ();
Object s3 = new Student ();
1. 一个父类引用可以指向它的任何一个子类对象
Object o = new AnyClass ();
Person p = null ;
p = new Student ();
p = new Teacher ();
p = new Person ();
2. 多态中的方法调用
注:子类继承父类 , 调用 a 方法,如果 a 方法在子类中没有重写 , 那么就是调用的是子类继承父类的 a 方法 ,
如果重写了 , 那么调用的就是重写之后的方法。
Student s = new Student ();
Person p = new Student ();
变量 s 能调用的方法是 Student 中有的方法 ( 包括继承过来的 ), 变量 p 能调用的方法是 Person 中有的方法 (
括继承过来的 )
但是变量 p 是父类型的 ,p 不仅可以指向 Student 对象 , 还可以指向 Teacher 类型对象等 , 但是变量 s 只能指
Studnet 类型对象 , Student 子类型对象。变量 p 能指向对象的范围是比变量 s 大的。
Object
类型的变量 o, 能指向所有对象 , 它的范围最大 , 但是使用变量 o 能调用到的方法也是最少的 , 只能调用
Object 中的声明的方法 , 因为变量 o 声明的类型就是 Object.
注: java 中的方法调用 , 是运行时动态和对象绑定的 , 不到运行的时候 , 是不知道到底哪个方法被调用的。
2 、重写、重载和多态的关系
重载是编译时多态
重写是运行时多态
3 、多态的注意事项
1. 多态是方法的多态,属性没有多态性。
2. 编写程序时,如果想调用运行时类型的方法,只能进行类型转换。不然通不过编译器的检查。但是
如果两个没有关联的类进行强制转换,会报: ClassCastException 。 比如:本来是狗,我把它转成
猫。就会报这个异常。
3. 多态的存在要有 3 个必要条件:要有继承,要有方法重写,父类引用指向子类对象
4 、多态存在的条件
1. 有继承关系
2. 子类重写父类方法
3. 父类引用指向子类对象
那么以下三种类型的方法是没
有办法表现出多态特性的(因为不能被重写):
1. static 方法,因为被 static 修饰的方法是属于类的,而不是属于实例的
2. fifinal 方法,因为被 fifinal 修饰的方法无法被子类重写
3. private 方法和 protected 方法,前者是因为被 private 修饰的方法对子类不可见,后者是因为尽管被
protected 修饰的方法可以被子类见到,也可以被子类重写,但是它是无法被外部所引用的,一个
不能被外部引用的方法.
5、 instanceof 和类型转换
System . out . println ( x instanceof Y );
该代码能否编译通过 , 主要是看声明变量 x 的类型和 Y 是否存在子父类的关系 . " 子父类关 " 系就编译通过 ,
没有子父类关系就是编译报错 .
之后学习到的接口类型和这个是有点区别的。
System . out . println ( x instanceof Y );
输出结果是 true 还是 false , 主要是看变量 x 所指向的对象实际类型是不是 Y 类型的 " 子类型 " .
2. 类型转换
【为什么要类型转换】
// 编译报错 , 因为 p 声明的类型 Person 中没有 go 方法
Person p = new Student ();
p . go ();
// 需要把变量 p 的类型进行转换
Person p = new Student ();
Student s = ( Student ) p ;
s . go ();
或者
// 注意这种形式前面必须要俩个小括号
(( Student ) p ). go ();
【总结】
1 、父类引用可以指向子类对象,子类引用不能指向父类对象。
2 、把子类对象直接赋给父类引用叫 upcasting 向上转型,向上转型不用强制转型。
Father father = new Son();
3 、把指向子类对象的父类引用赋给子类引用叫向下转型( downcasting ),要强制转型。
father 就是一个指向子类对象的父类引用,把 father 赋给子类引用 son Son son = Son
father
其中 father 前面的( Son )必须添加,进行强制转换。
4 upcasting 会丢失子类特有的方法 , 但是子类overriding 父类的方法,子类方法有效
5 、向上转型的作用,减少重复代码,父类为参数,调有时用子类作为参数,就是利用了向上转型。这样
使代码变得简洁。体现了 JAVA 的抽象编程思想。
修饰符
1 static 修饰符
1 static 变量
在类中 , 使用 static 修饰的成员变量 , 就是静态变量 , 反之为非静态变量。
静态变量和非静态变量的区别
静态变量属于类的 ," 可以 " 使用类名来访问 , 非静态变量是属于对象的 ," 必须 " 使用对象来访问
静态变量对于类而言在内存中只有一个 , 能被类的所有实例所共享。实例变量对于类的每个实例都有一份 ,
它们之间互不影响
在加载类的过程中为静态变量分配内存 , 实例变量在创建对象时分配内存,所以静态变量可以使用类名来
直接访问 , 而不需要使用对象来访问 .
2 static 方法
在类中 , 使用 static 修饰的成员方法 , 就是静态方法 , 反之为非静态方法。
静态方法 " 不可以 " 直接访问类中的非静态变量和非静态方法 , 但是 " 可以 " 直接访问类中的静态变量和静态
方法
注意 :this super 在类中属于非静态的变量 .( 静态方法中不能使用)
: 为什么静态方法和非静态方法不能直接相互访问 ? 加载顺序的问题!
父类的静态方法可以被子类继承 , 但是不能被子类重写
父类的非静态方法不能被子类重写为静态方法 ;
 
3 、代码块和静态代码块
【类中可以编写代码块和静态代码块】
public class Person {
{
// 代码块 ( 匿名代码块 )
}
static {
// 静态代码块
}
}
【匿名代码块和静态代码块的执行】
因为没有名字 , 在程序并不能主动调用这些代码块。
匿名代码块是在创建对象的时候自动执行的 , 并且在构造器执行之前。同时匿名代码块在每次创建对象的
时候都会自动执行 .
静态代码块是在类加载完成之后就自动执行 , 并且只执行一次 .
: 每个类在第一次被使用的时候就会被加载 , 并且一般只会加载一次 .

public class Person {
{
System.out.println("匿名代码块");
}
static{
System.out.println("静态代码块");
}
public Person(){
System.out.println("构造器");
}
}
main:
Student s1 = new Student();
Student s2 = new Student();
Student s3 = new Student();
4 、创建和初始化对象的过程
Student 类之前没有进行类加载】
1. 类加载 , 同时初始化类中静态的属性
2. 执行静态代码块
3. 分配内存空间 , 同时初始化非静态的属性 ( 赋默认值 ,0/false/null)
4. 调用 Student 的父类构造器
5. Student 中的属性进行显示赋值 ( 如果有的话 )
6. 执行匿名代码块
7. 执行构造器
8. 返回内存地址
2 fifinal 修饰符
1 、修饰类
fifinal 修饰的类不能被继承 , 没有子类
2 、修饰方法
fifinal 修饰的方法可以被继承 , 但是不能被子类的重写
3 、修饰变量
fifinal 修饰的变量表示常量 ,
3 abstract 修饰符
abstract 修饰符可以用来修饰方法也可以修饰类 , 如果修饰方法 , 那么该方法就是抽象方法 ; 如果修饰类 ,
么该类就是抽象类。
1 、抽象类和抽象方法的关系
抽象类中可以没有抽象方法 , 但是有抽象方法的类一定要声明为抽象类。
3 、特点及作用
抽象类 , 不能使用 new 关键字来创建对象 , 它是用来让子类继承的。
抽象方法 , 只有方法的声明 , 没有方法的实现 , 它是用来让子类实现的。
接口
1 、接口的本质
普通类:只有具体实现
抽象类:具体实现和规范 ( 抽象方法 ) 都有!
接口:只有规范!
【为什么需要接口 ? 接口和抽象类的区别 ?
接口就是比 抽象类 抽象 抽象类 ,可以更加规范的对子类进行约束。全面地专业地实现了:
规范和具体实现的分离。
抽象类还提供某些具体实现,接口不提供任何实现,接口中所有方法都是抽象方法。接口是完全面
向规范的,规定了一批类具有的公共方法规范。
从接口的实现者角度看,接口定义了可以向外部提供的服务。
从接口的调用者角度看,接口定义了实现者能提供那些服务。
接口是两个模块之间通信的标准,通信的规范。如果能把你要设计的系统之间模块之间的接口定义
好,就相当于完成了系统的设计大纲,剩下的就是添砖加瓦的具体实现了。大家在工作以后,做系
统时往往就是使用 面向接口 的思想来设计系统。
2 、接口与抽象类的区别
抽象类也是类 , 除了可以写抽象方法以及不能直接 new 对象之外 , 其他的和普通类没有什么不一样的。接
口已经另一种类型了 , 和类是有本质的区别的 , 所以不能用类的标准去衡量接口。
声明类的关键字是 class, 声明接口的关键字是 interface
抽象类是用来被继承的 ,java 中的类是单继承。
A 继承了抽象类 B, 那么类 A 的对象就属于 B 类型了 , 可以使用多态
一个父类的引用 , 可以指向这个父类的任意子类对象
: 继承的关键字是 extends
接口是用来被类实现的 ,java 中的接口可以被多实现。
A 实现接口 B C D E.., 那么类 A 的对象就属于 B C D E 等类型了 , 可以使用多态
一个接口的引用 , 可以指向这个接口的任意实现类对象
: 实现的关键字是 implements
3 、接口中的方法都是抽象方法
4 、接口中的变量都是静态常量 (public static fifinal 修饰 )
一般接口中不写变量   只写方法
5 、一个类可以实现多个接口
6 、一个接口可以继承多个父接口
内部类
匿名内部类
什么是匿名对象?如果一个对象只要使用一次,那么我们就是需要 new Object().method() 。 就可以
了,而不需要给这个实例保存到该类型变量中去。这就是匿名对象。
public class Test {
public static void main(String[] args) {
//讲new出来的Apple实例赋给apple变量保存起来,但是我们只需要用一次,就可以这样写
Apple apple = new Apple();
apple.eat();
//这种就叫做匿名对象的使用,不把实例保存到变量中。
new Apple().eat();
}
}
class Apple{
public void eat(){
System.out.println("我要被吃了");
}
}


匿名内部类跟匿名对象是一个道理:
匿名对象:我只需要用一次,那么我就不用声明一个该类型变量来保存对象了,
匿名内部类:我也只需要用一次,那我就不需要在类中先定义一个内部类,而是等待需要用的时候,我
就在临时实现这个内部类,因为用次数少,可能就这一次,那么这样写内部类,更方便。不然先写出一
个内部类的全部实现来,然后就调用它一次,岂不是用完之后就一直将其放在那,那就没必要那样。
1. 匿名内部类需要依托于其他类或者接口来创建
如果依托的是类 , 那么创建出来的匿名内部类就默认是这个类的子类
如果依托的是接口 , 那么创建出来的匿名内部类就默认是这个接口的实现类。
2. 匿名内部类的声明必须是在使用 new 关键字的时候
匿名内部类的声明及创建对象必须一气呵成 , 并且之后能反复使用 , 因为没有名字。
main :
A a = new A (){
// 实现 A 中的抽象方法
// 或者重写 A 中的普通方法
};
: 这个大括号里面其实就是这个内部类的代码 , 只不过是声明该内部类的同时就是要 new 创建了其对象 ,
并且不能反复使用 , 因为没有名字。
例如 :
B 是一个接口,依托于 B 接口创建一个匿名内部类对象
B b = new B (){
// 实现 B 中的抽象方法
};
public static void main(String[] args) {

        // 通过一个类的方式匿名内部类
        //实现A中的抽象方法
        // 或者重写A中的普通方法
        new Persion() {
            @Override
            public void st() {
                System.out.println("234");
            }
        }.st();   // 可以直接在后面调用方法

        // 通过接口实现匿名内部类  也可以创造一个对象调用,推荐使用直接在后面调用
        Car car = new Car() {
            @Override
            public void run() {
                System.out.println("汽车也可以实现匿名内部类");
            }
        };


        car.run();

1. 匿名内部类除了依托的类或接口之外 , 不能指定继承或者实现其他类或接口 , 同时也不能被其他类所
继承 , 因为没有名字。
2. 匿名内部中 , 我们不能写出其构造器 , 因为没有名字。
3. 匿名内部中 , 除了重写上面的方法外 , 一般不会再写其他独有的方法 , 因为从外部不能直接调用到。 (
接是调用到的 )
只能使用这一次,我们知道了这是一个类, 将其 new 出来,就能获得一个实现了 Test1 接口的类的实例
对象,通过该实例对象,就能调用该类中的方法了,因为其匿名类是在一个类中实现的,
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值