Java 面向对象编程(OOP)
人类思想的方法原则的高深体现:抽象,分类,继承,聚合,多态
基于java尚硅谷教程的学习笔记,以及自己的一些理解和新知识分享
文章目录
一、前言
(一)面向对象的三大特征
- 封装
- 继承
- 多态
(二)面向对象核心思想
-
Object–对象和Class–类是面向对象的核心概念
-
Class–类是一类事物的抽象定义
-
Object–对象是实际存在的该类事物的个体,是类的实例化
-
万事万物皆对象
二、Class–类
-
Class中的Member(成员)
- 属性(Field) = 成员变量
- 方法(Method) = 函数/成员方法
-
类的语法格式
修饰符 class 类名{ 属性声明; 方法声明; } 修饰符:缺省,public,private(这个私有类定义只能是内部或者嵌套类)
-
类的访问机制
- 一个类中的访问机制:类中方法直接访问类中成员变量(例外:static方法访问非static,编译不通过)
- 不同类中访问机制:先创建对象,再用对象访问类中定义的成员
三、Object对象
(一)使用对象
Person p1 = new Person();
Person p2 = new Person();
(二) 对象的生命周期
(三)对象内存解析
堆(Heap):存放对象实例和数组
栈(Stack):存储局部变量,对象引用(对象在堆内的首地址),方法执行完自动释放
方法区(Method Area):用于存储已经被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据
(四)对象内存细致解析
(五)匿名对象
- 不定义对象的句柄,直接调用对象的方法
- new person().shout();
- 使用情况
- 一个对象只需要进行一次方法调用
- 将匿名对象作为实参传递给一个方法调用(工程思想)
二、类的成员
(一)属性Field
-
语法格式
修饰符 数据类型 属性名 = 初始化值; -修饰符:private,缺省,protected,public,static,final -数据类型:基本数据类型+引用数据类型 -属性名:标识符,符合命名规范即可 public class Person{ private int age; public String name = "CalvinHaynes" }
-
变量分类
- 成员变量(方法体外,类体内)–有默认初始化值
- 实例变量(非static)
- 类变量(static)
- 局部变量(方法体内)–必须显示初始化
- 形参(方法、构造器中定义的变量)
- 方法内局部变量
- 代码块内局部变量
- 成员变量(方法体外,类体内)–有默认初始化值
-
成员变量和局部变量的区别
-
属性的默认初始化赋值
(二)方法Method
对象所能实现的功能封装,便于简化代码,实现代码复用
1、 声明格式
修饰符 返回值类型 方法名(形参列表){
方法体
return 返回值;
}
修饰符:public,private,protected,缺省
返回值类型:void(无返回值),其他数据类型
2、方法分类
3、调用方法时的内存调度
注意事项:方法中只能调用方法或者属性,不可在方法内部定义方法
4、方法重载(overload)
-
同一类中,允许存在一个以上的同名方法,只要参数类型或参数个数不同即可
-
确定指定的方法:先看方法名,再看参数列表
-
判断是否是重载,只与方法参数个数和类型的不同有关,与方法的权限修饰符,返回值类型,形参变量名,方法体都没有关系
public void man(int age){ } public void man(String name,int age){ } public void man(){ }
5、可变个数的形参
- 声明格式:方法名(参数类型名 …参数名)
- 方法参数部分指定类型的参数个数是可变多个,可以传入任意数量参数
- 可变参数方法使用和方法参数部分使用数组是一样的
- 可变个数形参的方法与同名方法也构成重载
- 方法的参数中如果有可变个数形参一定要放在最后面(认真思考一下,如果可变个数形参放在参数列表的第一个或中间会出现什么效果)
- 在一个方法的形参位置,最多只能声明一个可变个数形参
public void test(String ...books){
}
public void test(String[] args){
}
public void test(String book){
}
public void test(int num,String name,String ...books){
}
6、方法参数的值传递机制
- 方法参数
- 形参:声明时的餐宿
- 实参:实际传给形参的值
- Java参数的值如何传入方法呢?
- 参数传递方式只有一种:值传递
- 值传递的分类
- 形参是基本数据类型:将实参基本数据类型变量的“数据值”传递给形参
- 形参是引用数据类型:将实参引用数据类型变量的“地址值”传递给形参
7、两道有趣的题目
1、貌似是考察方法的参数传递
//方法一
public static void method(int i,int j) {
i = 100;
j = 200;
System.out.println("a = " + i + " b = " + j);
System.exit(0);
}
2、微软面试题
//误区:从头到尾遍历,第一个除完第一个第一个值变为1了
//错误写法
for(int i = 0li < arr.length;i++){
arr[i] = arr[i] / arr[0];
}
//最简便写法,从后向前遍历
for(int i = arr.length - 1;i >= 0;i--){
arr[i] = arr[i] / arr[0];
}
//另一种写法
int temp = arr[0];
for(int i = 0;i < arr.length;i++){
arr[i] = arr[i] / arr[0];
}
8、递归方法(recursion)
- 递归:自己调用自己(方法体内调用方法本身)
- 递归是一种隐式循环的实现,重复执行代码但是不需要循环控制流程结构
- 递归的注意事项
- 一定要向已知方向递归
- 一定要有结束条件
三、面向对象特征:封装和隐藏
防止使用者对类中成员的直接操作导致数据错误、混乱、安全性泄露或程序错误执行
(一)思想
- 通过定义访问权限来封装和隐藏信息
- 隐藏属性(private):隐藏类中无需对外的技术细节(其实也是公司企业的一种知识产权的表现,同时防止误操作属性使得整个程序运行异常)
- 封装方法:使用者只能通过事先定义好的方法来访问数据(这样设置的好处是方便加入控制逻辑,限制对属性的不合理操作)
- 便于修改,增强可维护性
(二)四种访问权限修饰符
注意:对于class的权限修饰只可以用public和default(缺省)
- public类可以在任意地方被访问
- default类只可以被同一个包内部的类访问
class Animal{
private int legs;
public void setLegs(int i){
if(i != 0 && i != 2 && i != 4){
System.out.println("wrong number of legs!");
return;
}
legs = i;
}
public int getLegs(){
return legs;
}
public class Zoo{
public static void main(String[] args){
Animal xb = new Animal();
xb.setLegs(4);
System.out.println(xb.getLegs());
}
}
}
四、构造器(3W法讲解)
(一)what?
- 构造器是与类相同名称的一个构造方法
(二)why?
- 为了创造对象时初始化成员属性(new对象时)
- java在创建对象时,会在使用对象之前调用相应的构造器,确保每次对象都能够正确初始化(是C语言每次都要调用初始化函数的升级版,也是防止程序员忘记初始化的一个很牛皮的语法)
(三)how?
- 语法格式
修饰符 类名(参数列表){
初始化语句;
}
//示例
public class Person{
private int age;
public Person(){
age = ;
}
public Person(int age){//构造器重载
this.age = age;
}
public int getAge(){
return age;
}
public void setAge(int age){
this.age = age;
}
}
-
分类
- 隐式无参构造器(系统默认)–未定义构造器时,其实系统默认就已经有一个无参构造器了
- 显示定义一个或多个构造器(无参、有参)
-
注意:
- java中,每个类至少有一个构造器
- 默认构造器修饰符与所属类的修饰符一样
- 一旦显式定义了构造器,系统不再提供默认构造器
- 一个类可以创建多个重载构造器
- 父类的构造器不可以被子类继承
JavaBean:Java语言写成的可重用组件
- 类是公共的
- 属性是private的
- 有对应的public的get、set方法
关于JavaBean,之后了解深刻之后单独出一篇博客
五、关键字this(3W)
(一) what?
- 顾名思义,this即代表了当前“这个”东西,有点抽象,接着往下看
(二)why?
- 在方法内部使用时,可以用this引用该方法所属类
- 在构造器内部使用,this表示该构造器正在初始化的东西
(三)how?
-
在任意方法或构造器内,如果使用当前类的成员变量或成员方法可以在其前面添加this,增强程序的阅读性。不过,通常我们都习惯省略this。
-
当形参与成员变量同名时,如果在方法内或构造器内需要使用成员变量,必须添加this来表明该变量是类的成员变量
-
使用this访问属性和方法时,如果在本类中未找到,会从父类中查找
-
this可以作为一个类中构造器相互调用的特殊格式
class Cat{
private String name;
private int age;
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setAge(int age) {
this.age = age;
}
public int getAge() {
return age;
}
public Cat() {
String info = "Cat初始化时,需要考虑如下的1,2,3,4...共40行代码";
System.out.println(info);
}
public Cat(String name) {
this();
this.name = name;
}
public Cat(int age) {
this();
this.age = age;
}
public Cat(String name,int age) {
this(age);
this.name = name;
}
}
六、关键字:package、import
(一)package
1、what and how?
-
package语句作为Java源文件的第一条语句,指明该文件中定义的类所在的包。(若缺省该语句,则指定为无名包)。它的格式为:
package 顶层包名.子包名子包名 ; -
包对应于文件系统的目录,package语句中,用语句中,用 “.” 来指明包来指明包(目录目录)的层次;
-
包通常用小写小写单词标识。通常使用所在公司域名的倒置:com.atguigu.xxx
2、why?
- 包帮助管理大型软件系统:将功能相近的类划分到同一个包中。比如:MVC的设计模式(以后会单独出blog)
- 包可以包含类和子包,划分项目层次,便于管理
- 解决类命名冲突的问题
- 控制访问权限
(二)import
- 在源文件中使用import显式的导入指定包下的类或接口
- 声明在包的声明和类的声明之间。
- 如果需要导入多个类或接口,那么就并列显式多个import语句即可
- 举例:可以使用java.util.*的方式,一次性导入util包下所有的类或接口。
- 如果导入的类或接口是java.lang包(java language,默认全局包)下的,或者是当前包下的,则可以省略此import语句。
- 如果在代码中使用不同包下的同名的类。那么就需要使用类的全类名的方式指明调用的
是哪个类。 - 如果已经导入java.a包下的类。那么如果需要使用a包的子包下的类的话,仍然需要导入。
- import static组合的使用:调用指定类或接口下的静态的属性或方法
个人博客地址:CalvinHaynes’s Blog
初来乍到,请多多指教