Java基础-----面向对象
文章目录
- 一、类和对象
- 二、面向对象三大特征
- 三、内存的底层分析
- 四、特殊类
- 五、 总结
一、类和对象
1、面向对象和面向过程
1.1、面向对象和面向过程的理解图
面向对象和面向过程都是一种思维
比如小朋友去上学,想步骤(比如上学:起床—>走路---->到学校)
比如车的组装:会想车的组成部分(比如:车灯 座椅等等)
(肯定不会去想车的轮子怎么去做)(关于车的轮子怎么做是由面向过程去做的)
1.2、面向过程和面向对象的区别
1.2.1、相同点
1.2.2、不同点
**面向过程**适合简单、不需要协作的事务、重点关注如何执行.
面向过程时、我们首先思考"怎么按步骤实现?" 并且将步骤对应成方法,一步一步,最终完成.这个适合简单任务,
不需要过多协作的情况下.比如开车?其步骤:
**面向对象**((oriented-Object)思想)更契合人的思想模式.我们首先思考怎么设计这个事务?“
比如去组装一辆车?而不是按照步骤造车的问题.我们会从"车是由什么组成"开始是靠.
发现,车由如下对象组成:
1.2.3、奇妙的地方
为了组装车,我门会去找轮胎厂、玻璃厂等等,但是具体到轮胎厂的一个流水线操作,仍然是有步骤的
还是离不开面向过程思维(面向对象和面向过程相辅相成)
因此,面向对象可以帮助我们从宏观上把握,从整体上分析整个系统。
但是具体到实现部分的微观操作(就是一个一个方法),仍然需要面向过程的思路去处理
1.3、面向对象和面向过程思想的总结
1. 都是解决问题的思维方式、都是代码组织的方式
2. 面向过程是一种"执行者思维"、解决简单的问题可以使用面向过程
3. 面向对象是一种"设计者思维"、解决复杂、需要协作的问题可以使用面向对象
4. 面向对象离不开面向过程:
a、宏观上:通过面向对象进行整体的设计
b、微观上:执行和处理数据,仍然是面向过程
2、类
2.1、类和对象的图
大巴士的模型(看成是类)
大巴士(看成是对象)
2.2、类和对象的关系
类可以看做一个模板、或者图纸,系统根据类的定义来造出对象.我们需要造出航天飞机,怎么造?
类就是这个图纸、规定了汽车的详细信息、然后根据图纸将汽车造出来
2.3、类和对象的专业术语
类:我们叫做class
对象:我们叫做Object,instance (实例)。以后我们说某个类的对象、某个类的实例
2.4、类和对象的总结
类可以看作一类对象的模板,对象可以看成该类的一个具体实例
类是用于描述同一类型的对象的一个抽象概念、类中定义了这一类对象所具体的共同的属性、方法
2.5、类的定义
类中还有三种成员:属性(field)、方法(method)、构造器(constructor)
2.5.1、类中的属性(field成员变量)
2.5.1.1、属性的定义
**属性用于定义该类或该类对象包含的数据或者说静态特征。**
属于作用范围是整个类体.
在定义成员变量时可以对其初始化,如果不对其初始化,**Java使用默认的值对其初始化**
2.5.1.2、成员变量的默认值
2.5.2、类中的方法
2.5.2.1、方法的定义
方法用于定义该类或该类实例的行为特征和功能实现.
方法是类和对象行为特征的抽象
面向过程中,整个程序的基本单位是类 ,方法是从属于类和对象的
2.5.3、类中的构造器
2.5.3.1、创建对象的步骤
2.5.3.2、构造器的声明格式
2.5.3.3、构造器4给要点
1. 构造器通过new关键字调用
2. 构造器虽然有返回值、不能定义返回值类型(因为返回类型肯定是本类,没有意义的),不能在构造器里面使用return返回某个值
3. 如果我们没有定义构造器,则编译器会自动定义一个无参的构造方法,如果已定义则编译器不会自动添加
4. 构造器的方法名必须和类名一致
2.5.3.4、构造器方法的重载
public Student(int id, int age, String name) {
this.id = id;
this.age = age;
this.name = name;
}
public Student(int id, int age) {
this.id = id;
this.age = age;
}
2.5.4、编写一个学生类
package com.company.opp;
public class Student {
int id ;
int age ;
int name ;
public void study(){
System.out.println("正在学习中....");
}
public void kickSoccer(){
System.out.println("正在踢球中....");
}
}
2.5.4、类的管理
2.5.4.1、包机制
2.5.4.2、包的要点
注意事项:写项目的时候都要加上包,不要使用默认包
com.wr和com.wr.oyc 这两个包没有包含关系,是两个独立的包。只是逻辑上看起来后者是前者的一部分
2.5.4.3、JDK中主要的包
2.5.4.4、包的静态和属性的静态导入
package com.company.package1;
import static java.lang.Math.*;
import static java.lang.Math.PI;
public class Demo {
public static void main(String[] args) {
// 静态导入包之后不需要Math.pow()
System.out.println(pow(1,2));
// 导入静态属性
System.out.println(PI);
}
}
2.5.4.5、类重名问题
package com.company.package1;
public class Demo04 {
public static void main(String[] args) {
// 我向导入pa包下的Dog类 但是和这个包下的Dog类同名了
com.company.pa.Dog dog = new com.company.pa.Dog();
}
}
class Dog{
}
2.6、String类
2.6.1、字符串的特点
2.6.2、String类和常量池
3、对象
3.1、对象和类的关系
3.1.1、类和对象的图
大巴士的模型(看成是对象)
大巴士(看成是类)
3.1.2、类和对象的关系
类可以看做一个模板、或者图纸,系统根据类的定义来造出对象.我们需要造出航天飞机,怎么造?
类就是这个图纸、规定了汽车的详细信息、然后根据图纸将汽车造出来
3.1.3、类和对象的专业术语
类:我们叫做class
对象:我们叫做Object,instance (实例)。以后我们说某个类的对象、某个类的实例
3.1.4、类和对象的总结
类可以看作一类对象的模板,对象可以看成该类的一个具体实例
类是用于描述同一类型的对象的一个抽象概念、类中定义了这一类对象所具体的共同的属性、方法
3.2、对象的生命周期
3.2.1、创建对象四步骤
3.2.2、使用对象
通过变量引用操作对象
3.2.3、回收对象
对象没有被变量使用,则被认为是"垃圾",会被垃圾回收站回收
二、面向对象三大特征
1、继承
1.1、继承的作用
1、代码复用、更加容易实现类的扩展
2、方便建模
1.2、继承图以及实现
通过extends关键字来实现继承
1.3、instanceof的用法
instanceof是二元运算符、左边是对象,右边是类;
当对象是右边类或子类所创建对象时,返回true,否则,返回false比如;
package com.company.opp;
public class Main {
public static void main(String[] args) {
Person person = new Student("欧阳冲",12,19);
Person person1 = new Person("asd");
if(person instanceof Person){
System.out.println(true);
}
}
}
1.4、继承使用要点
1. 父类也称为超类、基类。 子类:派生类等
2. Java中只有单继承、没有像C++那样的多继承 。多继承会引起混乱,始继承链过于复杂,系统难以维护
3. Java中类没有多继承,接口有多继承
4. 子类继承父类,可以得到父类的全部属性和方法(除了父类的构造方法),但不见的可以直接访问(比如,父类的私有的属性和方法)
5. 如果定义一个类的时候,没有调用extends,则它的父类是:java.lang.Object
1.5、override(重写)
1.5.1、重写的要求
子类重写父类的方法,可以自身行为替换父类行为. 重写是实现多态的必要条件
方法重写需要符合下面三个要点
1. "==":方法名、型参列表相同
2. "<=":返回值类型和声明一异常类型,子类小于等于父类
3. ”>=“:访问权限,子类大于等于父类
1.6、final变量
1.7、继承和组合
1.7.1、组合的作用
组合核心是"将父类对象作为子类的属性"
对于js-a 关系建议使用继承 ,has-a 关系建议使用组合
比如人类 和学生 使用继承
比如电脑和键盘建议使用组合
1.9、Object类(所有类的父类)
1.10、equals方法的重写
1.10.1、"=="和equals的区别
1.11、super关键字
1.11.1、super关键字的使用
1. super ”可以看作“是直接父类对象的引用. 可以通过super来访问父类中被子类覆盖的方法或属性
2. 使用super调用普通方法,语句没有位置限制,语句没有位置限制,可以在子类中随便调用
3. 在一个类中,若是构造方法的第一行没有调用super(...)或者是this(...);那么java默认都会调用super();含是调用super(),含义是调用父类的无参数构造器.。
1.11.2、super关键字的内存分析
package com.company.opp;
public class TestSuper {
public static void main(String[] args) {
FatherClass fatherClass = new SonClass();
fatherClass.f();
}
}
class FatherClass{
int value ;
public void f(){
value = 100 ;
System.out.println("正在打印Father" + value);
}
}
class SonClass extends FatherClass{
int value ;
@Override
public void f(){
super.f();
value = 100 ;
System.out.println("正在打印Son" + value);
}
public void f2(){
}
}
1.11.3、继承树和super关键字
1、属性/方法查找顺序:(比如:查找变量value)
- 查找当前类中有没有value
- 依此上溯每个父类,查看每个父类中是否有value,直到Object
- 如果没找到变量h,则出现编译错误(直接报红)
- 上面步骤,只要找到h变量,则这个过程终止
2、构造方法调用顺序:
构造方法第一句总是:super(...)来调用父类对应的构造方法。
所以,流程就是:先向上追溯到Object,然后再依此向下执行类的初始化和构造方法,直到当前子类
3、静态初始化块调用顺序于构造方法调用顺序一样
package com.company.opp;
public class TestSuper {
public static void main(String[] args) {
FatherClass fatherClass = new SonClass();
// fatherClass.f();
}
}
class FatherClass{
int value ;
public FatherClass(){
System.out.println("正在执行FatherClass的构造方法");
}
public void f(){
value = 100 ;
System.out.println("正在打印Father" + value);
}
}
class SonClass extends FatherClass{
int value ;
public SonClass(){
System.out.println("正在执行SonClass的构造方法");
}
@Override
public void f(){
super.f();
value = 100 ;
System.out.println("正在打印Son" + value);
}
public void f2(){
}
}
注意在一个类的构造方法没有写super(),那么系统是会默认调用super()(调用父类的空构造方法)
如果调用了父类的有参构造方法那么系统就不会默认调用父类的空构造方法
1.12、复习题
2、封装
2.1、封装的作用和含义
2.2、封装在编程中的优点
- 提高代码的安全性
- 提高代码的复用性
- “高内聚”:封装细节.便于修改内部代码,提高可维护性
- "低耦合”:简化外部调用,便于调用者使用,便于扩展和协作
2.3、封装的实现----访问权限控制符
2.4、开发中封装的简单规则
3、多态
3.1、多态的定义
3.2、多态的要点
package com.company.polym;
public abstract class Animal {
String name ;
public abstract void shoot1 ();
public void shoot (){
System.out.println("动物正在吼叫");
}
}
class Dog extends Animal{
@Override
public void shoot1() {
}
@Override
public void shoot() {
System.out.println("小狗正在叫");
}
public void seeDoor(){
System.out.println("小狗正在看门");
}
}
class Cat extends Animal{
@Override
public void shoot1() {
}
@Override
public void shoot() {
System.out.println("小猫正在叫");
}
public void playClaw(){
System.out.println("小狗正在玩爪子");
}
}
package com.company.polym;
public class PolymTest {
public static void main(String[] args) {
//向上转型(自然转型)
//父类的引用变量 指向子类对象
Animal animal = new Dog();
animal.shoot();
}
}
3.3、多态的转型
package com.company.polym;
public class PolymTest {
public static void main(String[] args) {
//向上转型(自然转型)
//父类的引用变量 指向子类对象
Animal animal = new Dog();
// System.out.println(animal);
animal.shoot();
// 向下转型(强制转型)
// 子类的引用变量 指向 向上转型的父类的引用变量
// 需要在向上转型的父类的引用变量前面加上子类类型(例如Dog)
Dog dog = (Dog) animal ;
System.out.println(dog);
dog.seeDoor();
// 转型相当于戴不同帽子的作用
// 对象还是那个对象
// 怎么防止ClassCastException的出现?
// 关键字instanceof来体现
// if(animal instanceof Cat){
// Cat cat = (Cat)animal;
// System.out.println(cat);
// cat.playClaw();
// }
}
}
第一种情况(强转后能够正常运行)
如果这里不给animal前面加一个(Dog)转型的话,编译是通不过的
因为animal是父类的引用变量
这里创建的对象是Dog对象,父类引用变量animal指向了子类对象(Dog)
左边是Dog类,右边的父类引用变量animal指向了Dog类
必须加上(Dog)才不会报错
第二种情况(强转后会报错)
这个错误是类型强转错误
很简单的原因,就是animal是父类的引用变量指向的是Dog类
现在让Cat类的引用变量去指向animal(不就相当于指向了Dog类)
自然会报错
三、内存的底层分析
3.1、Java虚拟机内存模型概念
3.2、虚拟机的内存分布:
3.2.1、栈(虚拟机栈简称为栈)
1. 栈描述的是方法执行的内存模型,每个方法被调用都会创建一个栈帧(存粹局部变量、操作数、方法出口等)
2. JVM为每个线程创建一个栈,用于存放该线程执行方法的信息(实际参数、局部变量等)
3. 栈属于线程私有、不能实现线程间的共享
4. 栈的存储特性是"先进先出,后进后出"
5. 栈是由系统自动分配,速度快!栈是一个连续的内存空间
3.2.2、堆
1. 堆用于存粹创建好的对象和数组(数组也是对象)
2. JVM只有一个堆、被所有的线程共享
3. 堆不是一个连续的内存空间,分配灵活,速度慢
4. 堆被所有的线程所共享,在堆的区域,会被垃圾回收期做进一步划分,例如 新生代、老年代的划分
3.2.3、方法区
1. 方法去是Java虚拟机规范,可以有不同的实现
a、JDK以前是永久代
b、JDK部分去除了"永久代",静态变量、字符串常量池都挪到了堆内存中
c、JDK8是“元数据空间”和堆结合在一起
2. 、JVM只是一个方法区、被所有线程共享
3.、方法区实际也是堆,只是用于存储类、常量相关的信息
4、用来存放程序中永远不变或唯一的内容(类信息【Class对象等】 静态变量、字符串常量等)
5、常量池主要存放常量:如文本字符串、final常量
3.3、程序执行过程中内存分析******
3.4、参数传值机制
3.4.1、基本数据类型参数的传值
3.4.2、引用类型参数的传值
3.5、垃圾回收机制原理
3.5.1、垃圾回收原理的算法
3.5.1.1、内存管理
3.5.1.2、垃圾回收过程
3.5.1.3、垃圾回收相关算法
3.5.1.3.1、引用计数法
3.5.1.3.2、引用可达法
3.6、分代垃圾机制
3.6.1、作用
3.6.2、年轻代
3.6.3、年老代
3.6.4、永久代
3.6.5、模型以及讲解
一、Minor GC:用于清理年轻代区域,Eden区满了就会触发Minor GC清理无用对象,将有用的对象复制
到"Survivor1"、"Survivor2"区中
二、Major GC:用于清理老年代区域
三、Full GC :用于清理年轻代、老年代.成本较高、会对系统性能产生影响
3.6.6、JVM调优和Full GC
3.6.7、内存泄漏
3.7、作业
3.8、this关键字的本质
3.8.1、this关键字的用法
1、普通方法中,this总是指向调用该方法的对象
2、构造方法中,this关键字指向正要初始化的对象
3、this()调用重载的构造方法,避免相同的初始化代码,但只能在构造方法中使用,并且必须位于构造方法的第一句
4、this不能用于static方法中
5、在构造方法中使用this(…)必须放在第一位
6、this是作为普通方法的"隐式参数",由于系统传入到方法中
package com.company;
public class testThis {
int age;
String name ;
String sex ;
public testThis() {
System.out.println("正在初始化这个对象" + this);
}
public testThis(int age) {
this();
this.age = age;
}
public testThis(int age , String name) {
this(age);
this.name = name;
}
public testThis(int age, String name, String sex) {
this(age , name);
this.sex = sex;
}
void eat(){
System.out.println("该对象是" + this);
}
public static void main(String[] args) {
testThis testThis = new testThis();
testThis.eat();
}
}
3.9、static关键字的本质
3.9.1、static的要点
1、静态方法(类变量)、静态方法(类方法):static声明的属性或方法
2、静态变量/静态方法生命周期和类相同,在整个程序执行期间都有效。如下特点
a、为该类的公用变量、属于类,被该类的所有实例共享,在类载入时被初始化
b、static成员变量只有一份
c、一般使用"类名.类属性/方法"来调用
d、在static方法中不可直接访问非static的成员
package com.company.testStatic;
public class A {
int id ;
String name ;
static String company = "武侠公司 ";
public A(int id, String name) {
this.id = id;
this.name = name;
}
public void login (){
System.out.println(name);
}
public static void printCompany(){
System.out.println(company);
}
public static void main(String[] args) {
A a = new A(100 , "wr");
A.printCompany();
A.company = "武侠豪气公司" ;
A.printCompany();
}
}
3.9.1、静态初始块(继承树的追溯)
package com.company.testStatic;
public class A {
int id ;
String name ;
static String company = "武侠公司 ";
static {
printCompany();
A.company = "武侠豪气公司" ;
printCompany();
}
public A(int id, String name) {
this.id = id;
this.name = name;
}
public void login (){
System.out.println(name);
}
public static void printCompany(){
System.out.println(company);
}
public static void main(String[] args) {
// A a = new A(100 , "wr");
// A.printCompany();
// A.company = "武侠豪气公司" ;
// A.printCompany();
}
}
静态初始块:加载类就会执行静态初始块
3.10、变量的分类
四、特殊类
4.1、抽象类
4.1.1、抽象类的说明
package com.company.abstractClass;
public abstract class Demo1 {
public abstract void say();
}
4.1.2、抽象类的要点
4.2、抽象方法
4.3、接口
4.3.1、接口的理解
接口是一组规范
4.3.2、面向对象的精髓
4.3.3、接口的作用
4.3.3.1、为什么需要接口以及抽象和抽象类的区别
4.3.3.2、接口和实现类不是父子关系,是实现规则的关系
4.3.3.3、接口的定义和声明
4.3.3.4、接口的要点
4.3.3.4.1、接口中定义默认方法
4.3.3.4.1.1、默认方法的要点
4.3.3.4.2、接口中定义静态方法
4.3.3.4.2.1、静态方法的要点
1、Java8以后,可以在接口中定义静态方法的实现.这个静态方法直接从属于接口(接口也是类,一种特殊的类) 可以直接通过接口名调用
2、如果子类中定义了相同名字的静态方法,那就是完全不同的方法,直接从属于子类的静态方法可以直接通过子类名直接调用
package com.company.abstractClass;
public interface Honest {
default void helpOldMan(){
System.out.println("一定要老人");
}
void helpOther();
}
class GoodMan implements Honest{
public static void h (){
System.out.println("aaaaaaaa");
}
@Override
public void helpOther() {
System.out.println("我正在扶老奶奶过马路");
}
}
4.3.4、 接口的多继承
package com.company.abstractClass;
public interface A {
public void testA();
}
interface B{
public void testB();
}
interface C extends A ,B{
}
class D implements C{
@Override
public void testA() {
System.out.println("正在测试A");
}
@Override
public void testB() {
System.out.println("正在测试B");
}
public static void main(String[] args) {
C c = new D();
c.testA();
c.testB();
}
}
4.4、内部类
4.4.2、内部类的要点
注意:内部类只是一个编译时概念、一但编译成功,就会称为完全两个不同的两个类.
对于一个名为Outer的外部类和其他内部定义的名为Inner的内部类.
编译完成后出现Outer.class和Outer$Inner.class两个类的字节码文件
所以内部类是相对独立的一种存在,其成员变量可以和外部类的相同
4.4.1、内部类的分类
1. 成员内部类:a、非静态内部类 b、静态内部类
2. 匿名内部类
3. 局部内部类
4.4.2.1、成员内部类
4.4.2.1.1、非静态内部类:
4.4.2.1.2、静态内部类:
4.4.2.1.3、内部类的访问:
4.4.2.2 、匿名内部类
4.4.2.3、局部内部类
五、 总结
关于面向对象中类和对象 、面向对象的三大特征、内存的底层分析、特殊类都是我需要了解以及掌握,一起加油一起进步