文章目录
1、面向对象思想
1.1 概述
① 面向对象是相对于面向过程而言是把相关的数据和方法组织为一个整体来看待。
② 面向过程到面向对象,是程序员思想上从执行者到指挥者的转变。
1.2 举例
通过生活中的一个脑筋急转弯,来理解这个概念。
问:
把大象装进冰箱,需要几步?
面向过程的回答:
3步:1把冰箱门打开,2把大象装进去,3把冰箱门关闭
面向对象回答:
2步:1找一个能操作冰箱的人(对象),2指挥工人装大象
思考:
如果问题改成:把100只大象依次关进冰箱,共分几步?
面向过程的回答:此处需要省略N字。。。
面向对象的回答还是2步:
1招一个能操作冰箱的工人(对象),2指挥工人把大象依次装进去。
结论:
由上述例子得出,面向过程很死板,是很难变化的。面向对象更灵活,可复用性更高。
总结:面向过程适合小型开发,而面向对象跟适合中、大型开发(越大型越能体现面向对象的好处)。
1.3 三大思想
面向对象思想从概念上讲分为以下三种:OOA、OOD、OOP
OOA:面向对象分析(Object Oriented Analysis)
OOD:面向对象设计(Object Oriented Design)
OOP:面向对象程序(Object Oriented Programming)
1.4 三大特征
封装性:所有的内容对外部不可见。
继承性:将其他的功能继承下来继续发展。
多态性:方法的重载本身就是一个多态性的体现。
2、类与对象
2.1 两者关系
① 类表示一个共性的产物,是一个综合的特征,而对象是一个个性的产物,是一个个体的特征。
类相当于一张设计图纸,对象相当于一个(通过图纸构造出来的)实体。
根据手机设计图纸(类),设计的一个手机实体(对象)。
② 类必须通过对象才可以使用,对象的所有操作都在类中定义。
③ 类由属性和方法组成:
·属性:就相当于人的一个个的特征,例如:姓名、性别、年龄、性格、爱好、特长等等。
·方法:就相当于人的一个个的行为,例如:说话、吃饭、唱歌、跳舞、睡觉、开车等等。
2.2 类的定义格式
class 类名称{
//成员属性
//成员方法
}
2.3 属性与方法
属性定义格式:
数据类型 属性名;
属性定义并赋值的格式:
数据类型 属性名 = 初始值;
方法定义格式:
权限修饰符 返回值类型 方法名(形式参数列表){
//方法体
return 返回值;
}
2.4 对象的创建与使用
一个类要想真正的进行操作,则必须依靠对象,对象的定义格式如下:
类名称 对象名称 = new 类名称();
如果要想访问类中的属性或方法,则可以依靠以下的语法形式:
访问类中的属性:对象名.属性名;
调用类中的方法:对象名.方法名(实际参数列表);
示例代码段:
/**
* class 类名{
* 成员属性;
* 成员方法;
* }
*
* 类必须编写在.java文件中。
* 一个.java文件中,可以存在N个类,但是只能存在一个public修饰类。
* .java文件中的文件名称必须与public修饰的类名称完全一致。
*/
public class Demo{
//main()方法,程序的入口
public static void main(String[] args){
//创建对象的格式:
//类名 对象名 = new 类名();
Person person = new Person();
//对象属性赋值格式:
//对象名.属性名 = 值;
person.name = "小明";
person.age = 18;
person.sex = '男';
//对象方法的调用格式:
//对象名.方法名();
person.say();
System.out.println("1 + 2 + 3 = " + person.sum(1,2,3));
}
}
/**
* 人类
*/
class Person{
//属性-》特征
String name;
int age;
char sex;
//方法 -》行为
/**
* 返回值类型 方法名称(形式参数列表){
* 方法体
* return 返回值; //提示:若返回值类型为void,则为return;(或忽略)
* }
*/
//say()方法
void say(){
System.out.println("自我介绍:我是" + name + ",我的年龄:" + age + ",性别:" + sex);
}
//sum()方法
int sum(int x,int y,int z){
return x + y + z;
}
}
3、创建对象内存分析
3.1 栈(stack)
栈(Stack):Java中一个线程就有一个栈区,每个栈中的元素都是私有的,不被其他栈所访问。栈有后进先出的特点,栈中的数据大小与生存期都是确定的,缺乏灵活性,但是存取速度比堆要快,仅次于CPU中的寄存器...
存储速度快的原因:
栈内存,通过‘栈指针’来创建空间与释放空间!
指针向下移动,会创建新的内存;向上移动,会释放这些内存!
这种方式速度特别快,仅次于CPU寄存器!
但是这种移动的方式,必须要明确移动的大小和范围。
明确大小与范围是为了方便指针的移动,这是一个对于数据存储的限制,存储的数据大小是固定的,影响了程序员的灵活性~
所以我们把更大的数据存储到了堆内存中。
存储的是:
基本数据类型的数据 以及 引用数据类型的引用!
例如:
int a = 10;
Person person = new Person();
10存储在栈内存中,第二句代码创建的对象的引用“person”存储在栈内存中。
3.2 堆(Heap)
存放的是类的对象:
Java是一个纯面向对象语言,限制了对象的创建方式:类的对象是通过new关键字创建的。
new关键字,是指告诉JVM,需要明确的去创建一个新的对象,去开辟一块新的堆内存空间:
堆内存与栈内存不同,优点在于我们创建对象时,不必关注堆内存中需要开辟多少存储空间,也不需要关注内存占用时长!
堆内存中内存的释放是由GC(垃圾回收器)完成的
垃圾回收器回收堆内存的规则:
当栈内存中不存在此对象的引用时,则视其为垃圾,等待垃圾回收器回收!
示例图1:
示例图2:
3.3 方法区(Method area)
存放的是
- 类信息
- 静态的变量
- 常量
- 成员方法
方法区中包含了一个特殊的区域(常量池)(存储的是使用static修饰的成员)
3.4 PC寄存器
PC寄存器保存的是当前正在执行的JVM指令的地址!
在Java程序中,每个线程启动时,都会创建一个PC寄存器!
3.5 本地方法栈
保存本地(native)方法的地址!
4、构造方法(构造器(Constructor))
4.1 回顾对象创建
Person p = new Person(); //在创建对象的同时,就已调用无参构造方法,争对无参构造方法
Person p = new Person(实际参数列表); //在创建对象的同时,就已调用有参构造方法,争对有参或全参构造方法
在右侧Person后面出现的小括号,其实就是在调用构造方法!
4.2 概述
作用:
/*用于对象(对应类中的成员属性)初始化。*/
执行时机:
/*在创建对象时,自动调用构造方法。*/
特点:
所有的Java类中都会至少存在一个构造方法(即使未创建,系统默认给一个无参数的构造方法,且不可见)
如果一个类中没有明确的编写构造方法,则编译器会自动生成一个无参的构造方法,构造方法中没有任何的代码!
如果自行编写了一个有参构造器,则编译器不会再自动生成无参的构造器,作为规范需开发人员添加一个无参构造器。
4.3 定义格式
定义格式:
权限修饰符 类名称(形式参数列表){
方法体;
}
与普通方法基本相同,区别在于:方法名称必须与类名相同,/*没有返回值类型的声明!*/
案例:
public class Demo3{
public static void main(String[] args){
Person p = new Person(); //创建方法的同时,已调用构造方法,实现打印输出
p = new Person();
}
}
class Person{
public Person(){
System.out.println("对象创建时,此方法被调用");
}
}
4.4 构造方法设计(注意)
建议自定义无参构造方法,不要对编译器形成依赖,避免错误发生(不定)。
原因:当创建有参的构造器时,无参的构造器消失,此时创建对象时必须以带参数的形式创建对象,否则报错。
当类中有非常量成员变量时,建议提供两个版本的构造方法,一个是无参构造方法,一个是全属性做参数的构造方法(全参(类中的所有成员属性)构造方法)。
当类中所有成员变量都是常量或者没有变量时,建议不提供任何版本的构造。
示例代码:
public class Demo4{
public static void main(String[] args){
Person2 p = new Person2("小明",23); //特点,在创建构造方法的同时,构造方法执行,类中的成员属性初始化并打印
}
}
class Person2{
String name;
int age;
Person2(String name,int age){
this.name = name;
this.age = age;
System.out.println("姓名:" + name + ",年龄:" + age);
}
}
5 方法的重载
方法名称相同,参数类型或参数长度不同,可以完成方法的重载!方法的重载与返回值无关!
方法的重载,可以让我们在不同的需求下,通过传递不同的参数调用方法来完成具体的功能。
示例代码:
public class Demo5{
public static void main(String[] args){
Math m = new Math();
int num1 = m.sum(100,500); //根据 传递的参数类型 传递至 对应方法 对应参数类型吻合的方法中实现
System.out.println(num1);
double num2 = m.sum(12.3,23.3); //同理
System.out.println(num2);
double num3 = m.sum(12,12.5); //同理
System.out.println(num3);
}
}
// 命名规则 见名知意
class Math{
/**
* 一个类中定义的方法:是允许重载(相同的方法名称)
*
* 1、方法名称相同
* 2、参数列表长度 或 参数列表类型 或 参数顺序不同
*
* 注意:与返回值类型无关!
*/
int sum(int x,int y){
return x + y;
}
double sum(double x,double y){
return x + y;
}
double sum(int x,double y){
double x + y;
}
}
6 构造方法的重载
一个类,可以存在多个构造方法:
参数列表的长度或类型不同即可完成构造方法的重载~
构造方法的重载,可以让我们在不同的创建对象的需求下,调用不同的方法来完成对象的初始化!
示例代码:
public class Demo6{
public static void main(String[] args){
Person3 p1 = new Person3("小明",18);
p1.say(); //对应say()方法打印:自我介绍,姓名:小明,年龄:18
Person3 p2 = new Person3("小李");
p2.say(); //对应say()方法打印:自我介绍,姓名:小李,年龄:0
}
}
class Person3{
Person3(String name,int age){
this.name = name;
this.age = age;
}
Person3(String name){
this.name = name;
}
String name;
int age;
void say(){
System.out.println("自我介绍,姓名:" + name + ",年龄:" + age);
}
}
7 匿名对象
没有对象名称的对象,就是匿名对象。
匿名对象只能使用一次,因为没有任何的对象引用,所以将称为垃圾,等待被G·C回收。
只使用一次的对象可以通过匿名对象的方式完成,这一点在以后的开发中将经常使用到。
几种格式:
匿名对象的定义:new 类名称();
匿名对象的定义+成员属性初始化:new 类名称().成员属性名 = 初始值;
匿名对象的定义+成员方法的调用:new 类名称().成员方法名();
匿名对象的调用+成员方法传参的调用:new 类名称().成员方法名(实际参数); //常用1
匿名对象的定义+成员属性初始化并调用成员方法:new 类名称(实际参数).成员方法名(); //常用2
有返回值的成员方法,建议创建一个变量去接收它,eg:
System.out.print("Please input your name:");
String name = new Scanner(System.in).nextLine();
System.out.println("My name is" + name);
示例代码1:
public class Demo7{
/**
* 匿名:没有名字
*
*/
public static void main(String[] args){
int num = new Math2().sum(100,200); //匿名对象(将没有名称的对象调用sum()方法)
System.out.println(num);
}
}
class Math2{
int sum(int x,int y){
return x + y;
}
}
示例代码2:
public class Demo8{
/**
* 如果一个对象,我们准备使用两次或以上,那么一定要给对象 创建对象名。
*/
public static void main(String[] args){
//使用匿名对象的误区!!!
new Person5().name = "小明";
new Person5().age = 18;
new Person5().say();
}
}
class Person5{
String name;
int age;
void say(){
System.out.println("自我介绍,姓名:" + name + ",年龄:" + age);
}
}
图解(使用匿名对象的误区!!!):
package com.java.task1;
public class Test {
public static void main(String[] args) {
new Person().name = "小明";
new Person().age = 19;
new Person("小李",21).say();
}
}
/**
* 书类(非规范,因一个.java文件最好有且仅有一个类,且被public修饰)
* 这里是为了便于分析
*/
class Person{
String name;
int age;
void say() {
System.out.println("自我介绍,我是:" + name + ",今年:" + age + "岁。");
}
public Person() {
}
public Person(String name, int age) {
super();
this.name = name;
this.age = age;
}
}