面向对象的概念
面向对象OOP是一种编程范式,主要是将类型的特征和方法抽离出来,放到一个类型,统一管理,减少代码的重复类,提供可复用性和可维护性。
创建一个类并实例化
使用class创建一个类, name等叫做属性 或 成员变量 或字段
使用new创建一个对象,可以使用.来获取对象的属性或方法
public class QuickStart {
public static void main(String[] args) {
// 创建实例
Cat cat1 = new Cat();
cat1.name = "小黄";
cat1.age = 8;
cat1.weight = 2.3;
cat1.color = "#fdfdfd";
System.out.println("名字" + cat1.name + " 年龄" + cat1.age
+ " 体重" + cat1.weight + " 颜色" + cat1.color);
}
}
class Cat{
String name;
int age;
double weight;
String color;
}
属性的默认值
类的属性是有默认值的,所以即使你不给它赋值也可以使用。
它的默认值和数组的一样: int 0 short 0 byte 0 long 0 float 0.0 double 0.0 char \u0000 boolean false String null
成员方法
即方法,一些定义在类中的函数
使用成员方法可以提高代码的复用性,可以将实现的细节封装起来,然后供其他用户来调用
成员方法的结构
访问修饰符 返回数据的类型 方法名 (形参列表) {
// 方法体
语句;
return 返回值;
}
- 形参列表 表示用户输入的参数以及对应的类型
- 返回数据的类型 表示成员方法输出 没有返回值时为
void - return语句并不是必须的
一般例子
public class Method {
public static void main(String[] args) {
Person p = new Person();
p.name = "lczmx";
p.age = 100;
p.speak();
Person p2 = new Person();
p2.name = "山本";
p.say("我日!!", p2);
System.out.println(p.getAge());
}
}
class Person {
String name;
int age;
/*
1. 方法 成员方法
2. public表示公开
3. void 表示没有返回值
4. speak 是方法名 () 表示形参列表
5. {} 是方法体, 写我们要执行的的代码
*/
public void speak(){
System.out.println("我是一个好人");
}
// 使用形参
public void say(String words, Person p) {
System.out.println(words + " " + p.name);
}
// 返回参数, 并访问自身的属性
public int getAge(){
return this.age;
}
}
细节问题
- 访问修饰符(作用是控制方法使用的范围)
如果不写默认访问,(有四种:public,protected,默认,private),具体在后面说 - 返回数据类型
一个方法最多有一个返回值 (多个结果可以使用数组返回) - 返回类型可以为任意类型,包含基本类型或引用类型(数组,对象)
如果方法要求有返回数据类型,则方法体中最后的执行语句必须为return值;而且要求返回值类型必须和return的值类型一致或兼容
如果方法是void,则方法体中可以没有return语句,或者只写return; - 方法名
遵循驼峰命名法,最好见名知义,表达出该功能的意思即可 - 方法不能嵌套定义
调用机制
- 当程序执行到方法时,会开辟一个独立的栈空间
- 当方法执行完毕后或return后,就会返回,该方法的栈空间就会被销毁
- 返回到调用方法的地方,执行其他代码
- 当main方法执行完毕后,整个程序退出
示意图:
传参注意点
- 参数类型可以为任意类型,包含基本类型或引用类型
- 调用带参数的方法时,一定对应着参数列表传入相同类型或兼容类型的参数
- 方法定义时的参数称为形式参数,简称形参:方法调用时的传入参数称为实际参数,简称实参
- 实参和形参的类型要一致或兼容、个数、顺序必须一致
- 引用类型传递的是地址, 可以通过形参影响实参
- 基本数据类型,传递的是值(值拷贝),形参的任何改变不影响实参
方法重载
java中允许同一个类中,多个同名方法的存在,但要求形参列表不一致,这就是方法重载
重载的好处:
- 减轻了起名的麻烦
- 减轻了记名的麻烦
重载的要求:
- 方法名:必须相同
- 形参列表:必须不同 (形参类型或个数或顺序,至少有一样不同,参数名无要求)
- 返回类型:无要求
使用例子:
public class OverLoad {
public static void main(String[] args) {
MyCalculator calc = new MyCalculator();
System.out.println(calc.calculate(1, 1));
System.out.println(calc.calculate(1, 3.3));
System.out.println(calc.calculate(2.3, 1));
System.out.println(calc.calculate(1, 1, 10));
}
}
class MyCalculator {
public int calculate(int n1, int n2) {
return n1 + n2;
}
public double calculate(int n1, double n2) {
return n1 + n2;
}
public double calculate(double n1, int n2) {
return n1 + n2;
}
public int calculate(int n1, int n2, int n3) {
return n1 + n2 + n3;
}
}
可变参数
java允许将同一个类中多个同名同功能但参数个数不同的方法,封装成一个方法, 就可以通过可变参数实现
即参数个数不确定时(0个或多个),可以使用可变参数接收数据。
基本语法:
访问修饰符 返回类型 方法名 (数据类型... 形参名) {
}
注意:一个形参列表中只能有一个可变参数
使用例子:
public class VarParameter{
public static void main(String[] args) {
MyMethod method = new MyMethod();
System.out.println(method.sum(1,2,10,12));
System.out.println(method.showScore("lczmx", 1.1,2.123,99.2,12));
}
}
class MyMethod {
/**
1. int... 表示接受可变参数, 类型为int (可以接收0-多个int)
2. 使用可变参数时,可以当做数组使用
注意:
!!! 可变参数可以与普通参数一起使用, 但可变参数必须在后面
public int (int num, int... numbers) {}
!!! 一个形参列表中只能有一个可变参数
public int (String... arr1, int... arr2){} 报错!!
*/
public int sum(int... numbers){
int res = 0;
for (int i : numbers) {
res += i;
}
return res;
}
// 练习
public String showScore(String name, double... scoreArr) {
/**
有三个方法,分别实现返回姓名和两门课成绩(总分),返回姓名和三门课成绩(总分),
返回姓名和五门课成绩(总分)。封装成一个可变参数的方法
*/
double res = 0d;
for (double i : scoreArr) {
res += i;
}
return name + "的总成绩为: " + res;
}
}
作用域
- 在java编程中,主要的变量就是属性(成员变量)和局部变量
- 我们说的局部变量一般是指在 成员方法中定义的变量,作用域为定义它的代码块中
- 而全局变量就是属性,可以在整个类中使用,且可以通过
对象.xx的形式让外部类访问 - 全局变量(属性)可以不赋值,直接使用,因为有默认值,局部变量必须赋值后,才能使用,因为没有默认值
- 属性和局部变量可以重名,访问时遵循就近原侧
- 在同一个作用域中,比如在同一个成员方法中,两个局部变量,不能重名
- 属性生命周期较长,伴随着对象的创建而创建,伴随着对象的销毁而销毁。局部变量,生命周期较短,伴随着它的代码块的执行而创建,伴随着代码块的结束而销毁。
- 全局变量/属性可以加修饰符,局部变量不可以加修饰符
构造器
构造方法又叫构造器(constructor),是类的一种特殊的方法,它的主要作用是完成对新对象的初始化。
构造器基本语法:
[修饰符] 方法名 (形参列表) {
方法体;
}
注意点:
- 构造器的修饰符可以是默认
- 构造器没有返回值,它只是初始化对象而已
- 方法名必须和类名一样
- 参数列表规则和方法的一样
- 构造器的调用由系统完成
- java默认有一个空构造器,
类名(){},自定义后会被覆盖 (可以使用javap指令反编译查看)
一般的使用例子:
public class Constructor{
public static void main(String[] args) {
// 写了构造器函数 必须根据函数传值, 否则报错
Person p = new Person("lczmx", 18);
System.out.println(p.name);
}
}
class Person {
String name;
int age;
// ======= 一般使用
// 1. 名称一致
// 2. 形参形式和方法的一样
// 3. 没有返回值,不能写void
public Person(String name, int age){
this.age = age;
this.name = name;
}
}
this关键字
JVM会给每个对象分配this, 表示当前对象
- this关键字可以用来访问本类的属性、方法、构造器
- this用于区分当前类的属性和局部变量
- 访问成员方法的语法:
this.方法名(参数列表) - 访问构造器语法:
ths(参数列表):注意只能在构造器中使用(即只能在构造器中访问另外一个构造器,必须放在第一条语句) - this不能在类定义的外部使用,只能在类定义的方法中使用
使用例子:
/*
定义Person类,里面有name、age属性,并提供compareTo比较方法,用于判断
是否和另一个人相等,名字和年龄完全一样,就返回true,否则返回false
*/
public class This {
public static void main(String[] args) {
Person p1 = new Person("lczmx", 18);
Person p2 = new Person("lczmx", 20);
Person p3 = new Person("lczmx", 20);
System.out.println(p1.compareTo(p2));
System.out.println(p2.compareTo(p3));
}
}
class Person{
int age;
String name;
Person(String name, int age) {
this.age = age;
this.name = name;
}
public boolean compareTo(Person p) {
return p.age == this.age && p.name.equals(this.name);
}
}
使用其他构造器
一个类可以定义多个不同的构造器,即构造器重载
在构造器中可以使用this,访问其它构造器,但只能访问一次
使用例子:
public class Demo {
public static void main (String[] args) {
Employee e = new Employee("老王", '男', 29, "财务", 3000.8);
}
}
class Employee {
String name;
char gender;
int age;
String position;
double salary;
// 三个构造器
public Employee(String name, char gender, int age, String position, double salary){
this(name, gender, age);
// !! 只能用一个 不能复用两个
this.position = position;
this.salary = salary;
}
public Employee(String name, char gender, int age) {
this.name = name;
this.gender = gender;
this.age = age;
}
public Employee(String position, double salary) {
this.position = position;
this.salary = salary;
}
}
使用类在内存中的细节
比如有一个类:
class Person {
int age = 90;
String name;
Person (String name, int age) {
this.name = name;
this.age = age;
}
}
Person p = new Person("小王", 22);
加载类信息(之后加载一次)
在堆中分配空间(地址)
完成对象初始化
- 默认初始化,
age = 0 name=null - 显示初始化,
age= 90 - 构造器初始化,
age = 22 name = “小王”
- 默认初始化,
将对象在堆中的地址返回给
p
附上一张图,表示对象在内存中的形式
包
包的本质就是创建不同的俄文件夹、目录来保存文件。以达到三个作用:
- 区分相同名字的类
- 当类很多时, 可以很好的管理类
- 控制访问范围
一个包下包含很多类,java中常用的包有:
java.lang.*基本包,默认引入,无需手动引入java.util.*系统提供的工具包、工具类java.net.*网络包,网络开发java.awt.*做java界面开发GUI
定义方式
使用package定义一个包,需要放在类的最上面(即import在后面),每个类只能定义一个包。
包的命名规则:只能由字母、数字、下划线和.组成。不能是保留字和关键字。
一般的命名规范是:com.公司名.项目名.业务模块名(如:com.sina.crm.user com.sina.crm.user )
package com.xiaoming;
public class Dog {
}
导入
使用import导入包:
import java.util.Scanner;
// 也可以把包的所有类都导入(但不推荐)
import java.util.*;
访问修饰符
java提供四个访问修饰符,用于控制方法和属性(成员变量)的访问权限
private
用 private 修饰的类成员,只能被该类自身的方法访问和修改,而不能被任何其他类(包括该类的子类)访问和引用friendly(默认)
如果一个类没有访问控制符,说明它具有默认的访问控制特性。限定该类只能被同一个包中的类访问和引用,而不能被其他包中的类使用,即使其他包中有该类的子类protected
用保护访问控制符 protected 修饰的类成员可以被三种类所访问:该类自身、与它在同一个包中的其他类以及在其他包中的该类的子类public
只要包中的其他类在程序中使用 import 语句引入 public 类,就可以访问和引用这个类
使用例子:
package com.lczmx.modifier;
public class A {
public int n1 = 1; // 全部
protected int n2 = 2; // 同类 包 子类
int n3 = 3; // 同类 包
private int n4 = 4; // 同类
public void m1() {
System.out.println("n1 = " + n1 + "n2 = "
+ n2 + "n3 = " + n3 + "n4=" + n4);
}
}
继承
继承的概念和好处
继承可以解决代码复用问题, 所有的子类不需要重新定义这些属性和方法,通过extends来声明继承父类。
继承一般用法
基本语法:
class 子类 extends 父类 {
}
super关键字
对比this
- TODO
构造器问题
- TODO
寻找属性
- TODO
继承的内存布局
- TODO
封装
- TODO
多态
- TODO