java基础篇——面向对象
作者:xcbeyond
疯狂源自梦想,技术成就辉煌!微信公众号:《程序猿技术大咖》号主,专注后端开发多年,拥有丰富的研发经验,乐于技术输出、分享,现阶段从事微服务架构项目的研发工作,涉及架构设计、技术选型、业务研发等工作。对于Java、微服务、数据库、Docker有深入了解,并有大量的调优经验。
引言:
面向对象的思想正是Java学习的核心部分,要是没有搞懂面向对象,那么就称不上学过Java,因此,搞懂面向对象是至关重要的。对于初学者而言,首次接触面向对象时,总感觉怪怪的,不知道究竟在干什么(我刚开始接触也是这种感觉,渐渐的就找到感觉了),这其实都是正常现象的,不然怎么有人说他是很抽象的啊。面向对象,简单的理解就是把一切事物按照它自己本有存在的特征、属性通过自然组织语言组织起来,然后再用编程语言来实现。例如:人(类)本该就分有性别(男、女)、年龄、姓名等属性特征,然对于每一个而言,他们往往具体不同的这些属性特征值,于是就从“人”(类)这个类别中具体出来了每个人,即:类的实例化得到了对象。就可以对象他们进行相应的操作了。
面向对象(OO):
按照东西的特征和自然组织形式, 进行软件开发过程的组织, 是一个开发过程的方法论。
学习面向对象:
- 学习如何用OO语法描述事物的特征和自然组织形式.
- 学习面向对象思维的前提是朴素的哲学逻辑.
如: 多态, 抽象概念的具体实现是多态的,
如:美女是多态的!
一、类(Class):
它是一个复杂的数据结构,是把一类相似或相关联数据的相关操作封装在一起的一个集合。
1、类是用来描述一个领域模型中的具体概念(名词)的。
2、领域模型: 一个应用软件业务范畴, 也叫业务模型.
3、属性: 描述具体概念(事物)的特征.
如:<图书馆管理系统>中的概念: 书 Book
书的特征: 书号, 书名, 编号, 作者, 价格...
Java中类的写法(语法)如下:
修饰词 class 类名{
修饰词 类型 属性;
修饰符 返回值类型 方法名 {
// 方法体(实现类的相关操作)
}
}
如:
public class Book{
int id;
String name;
String[] authors;
String isbn;
double price;
}
二、对象:
1、 对象是类的具体实例!
比 如,书Book这个类,它只是代表了一类,你却不知道它到底是什么书,但你只知道它拥有哪些特点属性,即书名、书号、作者、书价等(类属性)信息,为了对书Book这个类具体化,就引出了“对象”的概念,因此,对象就是类的具体实例。如:《山楂树之恋》是一本书,《和空姐同居的日子》是一本书,他们属于Book类的两个不同的对象。
对象的创建是通过“new”运算符进行实例化的,即:
Book book = new Book();//book:引用 new Book():对象
看到这里,你或许还是一头雾水,请不必担心,先暂时记住就行了,随后你就会彻底明白了。new Book()它是真正的在内存中(准确的说是在“堆”内存中)创建了一个Book类的对象,此时在“栈”中创建了一个Book类型(类也属于一种数据类型,一种引用类型中的“类类型”)的引用变量book,最终将变量book的地址指向了new Book()创建的对象。<这里地址指向关系,是隐含存在的一种指针,可以这么理解,仅供理解而已。但java却是不存在指针的哦!> 。关于“堆”、“栈”可以参考《java核心内容——分配管理》了解。
引用:是指向具体对象的句柄,相当于自然语言的代词。
1> 代词本身不是对象,代词引用了一个具体对象。
2> 在特殊情况下引用(代词)可能指空。
3> 经常简单的叙述事物时候,不严格区别引用与对象。
如:
Book book = new Book();//book:引用 new Book():对象
book.name = "月子";
book.authors = new String[]{"白云","黑土"};
book = null;//book引用null
4>引用是null时候,访问属性或方法时候会出现: 空指针异常
如:
book = null;
System.out.println(book.name);//异常
2、构造器(构造方法):
在上面语句Book book = new Book()中,或许对用new Book()创建对象时,并不知道其真正的含义,其中Book()就是一个Book类的一个构造器(特殊的方法),用它来对对象的属性进行初始化。
构造器的使用:
1>、声明在类内部, 方法名与类名一致的方法叫构造方法, 构造方法不能声明返回值类型。
2>、构造方法可以包含参数, 参数一般是创建对象实例,必须依赖的条件(前提条件)。
如:
public Book(int id,String name,String isbn) {
this.id = id;
this.name = name;
this.isbn = isbn;
}
3>、构造方法经常会重载
方法重载:方法的重新书写,即重载
- 方法名一样
- 方法参数不一样
默认构造器:
对于每一个类都会存在一个构造器的,只是有些是使用的默认构造器而已,没有显式的显示出来。
1>、如果类没有声明任何构造器,Javac自动提供一个默认构造器, 无参数默认构造器。
2>、如果提供构造器声明, Javac将不再提供默认构 造器。
如:(这个程序只是为了说明默认构造器而已,没有其他实际价值)
/**
* 默认构造器的演示
* @author xcbeyond
*
*/
public class ConstructorDemo {
public static void main(String[] args) {
Foo foo = new Foo();
//Goo goo = new Goo();//错误,没有参数的构造器
//System.out.println(foo.a+","+goo.a);
//A 、编译错误 B、 1,0 C、 1,1 D、
}
}
class Foo {//没有显式的显示构造器,即使用默认构造器(无参构造器)
int a = 1;
}
class Goo{//没有无参构造器了
int a ;
public Goo(int a) {//默认无参构造器被重载成为了一个有参构造器
this.a = a;
}
}
new运算: 创建对象实例,如: Book book = new Book();
1、根据类的属性在堆中分配对象空间。
2、根据参数类型调用构造器。
3、new运算返回对象的引用地址。
对象的创建过程:
1、根据类的属性在堆中分配对象空间,并且自动初始化。
2、根据参数类型调用构造器。
this:
最大的作用就是让类中一个方法访问该类的另一个方法或属性。this可以代表任何对象。
- this 是对当前对象的引用, 是当前对象本身。
- 可以使用this明确的访问当前对象的属性或者方法。
- this() 是调用本类的其他构造器, 可以使用构造器的重用, 简化代码的实现.
- this() 必须写在构造器的第一行!
如:public Book(int id ,String name) {
//System.out.print(id);//错 ,this()必须写在第一行
this(id,name,null);
}
public Book(int id,String name,String isbn) {
this.id = id;
this.name = name;
this.isbn = isbn;
}
java方法参数的传递规则:
参数传递方式只有一种:值传递。值传递就是将实际参数值得副本(复制品)传入方法内,而参数本身不会受到任何影响。
1、基本类型就是其中值的复制, 引用类型是引用值(地址)的复制。
2、 变量的值:
- 基本类型的值是其本身
- 引用变量的值是一个地址值,是被引用对象的首地址
3、为了避免引用参数传递的副作用, 建议一切结果使用返回值带回。
如:
/**
* Java方法参数传递规则:基于值的传递,是变量值的复制
* 为了避免引用方法参数传递的副作用,建议一切结果使用返回值返回
* @author xcbeyond
*/
public class ParamaterDemo {
public static void main(String[] args) {
Koo koo = new Koo();
int a = 1;
update(a);
update(koo);
System.out.println("a="+a+",koo.a="+koo.a);//a=1,koo.a=2
int b = update2(a);
int c = update2(koo);
System.out.println("b="+b+",c="+c);//2,3
}
public static void update(int a ) {
a++;
}
public static void update(Koo koo) {
koo.a++;
}
public static int update2(int a ) {
a++;
return a;
}
public static int update2(Koo koo) {
koo.a++;
return koo.a;
}
}
class Koo {
int a = 1;
}
3、继承:
考虑到程序的实时扩展(添加新的属性、方法等操作),更好的进行维护,于是引入“继承”这个概念。它是在原有类的基础上添加或修改(重写)新的属性和方法。子类继承了父类的所有方法和属性。
用来表达类型概念上具体化,Java继承用extends 关键字。子类是父类的具体化,父类是子类的泛化(概念抽象化)
1>、子类继承父类的属性和方法
2>、构造器不能继承!
3>、实例化子类,会递归分配所有父类的空间
4>、子类默认调用父类的无参数构造器
继承特点:
1>、子类继承父类的属性和方法
2>、构造器不能继承
3>、创建子类实例,会递归分配所有父类的空间
4>、子类默认调用父类的无参数构造器
5>、子类可以覆盖(重写)父类的方法,修改父类行为
6>、JAVA只能单一继承
继承中的语法现象:
1>, 父类可以引用子类的实例,父类的实现是多态的。
2>, 子类可以覆盖父类的方法,修改父类的行为。
- 方法覆盖:子类覆盖了父类“相同方法签名”的方法。
- 方法的覆盖是由方法动态绑定实现的,就是java虚拟机运行时候确定执行那个方法,java最终执行子类的方法。
关于继承中的构造器:
1> 、子类递归调用父类构造器。
2> 、默认调用父类无参数构造器!
3> 、如果父类没有无参数构造器,就必须在子类中明确指定调用父类的有参数构造器!
4> 、使用super()调用父类构造器,必须写在子类构造器第一行。
5> 、编程建议:所有的类都提供无参数构造器!减少继承时候的麻烦。
如:
/**
* 子类构造器一定调用父类的构造器!
* @author xcbeyond
*
*/
public class ConstructorDemo {
public static void main(String[] args) {
Goo goo = new Goo();
System.out.println(goo.a);//5
}
}
class Foo extends Object {//任何类都继承Object类(超类)
int a = 1;
public Foo(int a) {
super();//Object类的构造器
this.a = a;
}
public void Foo() {//构造方法没有返回类型值,这里并不是构造方法,而是一个一般的方法而已!
}
}
//class Goo extends Foo{} //错 , 父类没有无参数构造器
class Goo extends Foo{
public Goo() {
//System.out.println();//super()必须放在构造器的第一行
super(5);//明确调用父类由参数构造器
}
}
对象的实例化过程
1>、 检查类是否加载,如果没有加载就加载这个类
- 如果有父类,要加载所有父类
- 懒惰式加载,如果第一次用到就加载,只加载一次
- 通过CLASSPATH指定的路径寻找类文件
- 加载以后是一个对象,类型是Class
2>、在内存堆中分配对象空间
递归分配所以父类属性空间,然后分别子类的空间,属性默认自动初始化,自动初始化为“0”值:null,0,false,\u0000
3>、执行属性的赋值
4>、递归调用父类构造器。(默认调用父类无参数构造器!)
5>、调用本类构造器
访问控制:
访问控制修饰词:public protected default private
- 声明属性和方法尽可能私有,这样才能做到尽可能封装
- 提供适当的属性访问方法,适当的开放属性的访问
- 不建议使用非公有类。就是说所有类都应该是公有的,并且一个源文件一个类
属性是静态绑定到变量类型。
方法是动态绑定,由最终对象的方法决定。
如:
/**
* 属性是静态绑定到变量类型
* 方法是动态绑定,有最终对象的方法决定
* @author xcbeyond
*
*/
public class FiledAccessDemo {
public static void main(String[] args) {
Goo goo = new Goo();
Foo foo = goo;
System.out.println(goo.a+","+goo.getA());//2,2
System.out.println(foo.a+","+foo.getA());//1,2
}
}
class Foo {
int a = 1;
public int getA() {
return a;
}
}
class Goo extends Foo {
int a = 2;
public int getA() {
return a; //retrun super.a;
}
}