Java基本语法(四)—— 面向对象(上)
类和对象
Class:对一类事物的描述,是抽象的定义。
Object:实际存在该类事物的个体,是实例(instance)。
设计类,就是设计类的成员。
- 属性(field/域/字段):对应类的成员变量
- 方法(method):对应类的成员函数
类和对象的使用步骤:
package com.coderleo.ClassTest;
/*
1.创建类、设计类的成员
2.创建类的对象
3.通过“对象名.属性名”/“对象名.方法名”调用对象结构
* */
public class PersonTest {
public static void main(String[] args) {
//2.实例化对象:类 类名 = new 类();
Person p1 = new Person();
//3.调用属性:对象名.属性名
p1.name = "wkm";
p1.isMale = true;
System.out.println(p1.age + " " + p1.name + " " + p1.isMale);
//1 wkm true
//3.调用方法:对象名.方法名
p1.eat();//人可以吃饭
p1.sleep();//人可以睡觉
p1.talk("Chinese");//人可以说话,使用的是:Chinese
}
}
//1.创建类、设计类的成员
class Person{
//属性
String name;
boolean isMale;
int age = 1;
//方法
public void eat(){
System.out.println("人可以吃饭");
}
public void sleep(){
System.out.println("人可以睡觉");
}
public void talk(String language){
System.out.println("人可以说话,使用的是:" + language);
}
}
多个对象的关系
创建了一个类的多个对象,则每个对象都独立地拥有一套类的属性(非static)。
接上面的代码:
Person p2 = new Person();
System.out.println(p2.name);//null
Person p3;
p3 = p1;//将p1的地址给了p3,所以p1、p3指向对空间中的同一块地方
System.out.println(p3.name);//和p1一样,都是“wkm”
p3.age = 10;
System.out.println(p1.age);//10
对象的内存解析
虚拟机栈:局部变量。
堆:存放new出来的结构(如:数组、对象);对象的属性(非static)加载在堆中。
方法区:类的加载信息、常量池、静态域。
具体例子:
属性(成员变量)和局部变量
属性:直接定义在类的{}内
局部变量:生命在方法内、方法形参、代码块内、构造器形参、构造器内部的变量
方法
声明:权限修饰符 返回值类型 方法名(形参列表){
方法体
}
static、final、abstract等后面讲。
-
权限修饰符:public、private、protected、缺省(封装时细说)
-
返回值:
- 对于有返回值的,需要return相应的类型。
- 无返回值的(void),可以不用return,或return;表示结束此方法。
-
方法名:做到见名知意
-
形参列表:0/多个;形式:类型1 形参1,类型2 形参2......
-
方法的使用中,可以调用当前类的属性、方法。
-
方法可以递归调用,但不可以在方法内定义新方法。
对象数组的内存解析
stus的每一个元素的默认初始值为null,在使用时要先new,否则就会像第五句一样出现空指针异常。
匿名对象
没有显式地赋值给对象一个变量,此类对象即为匿名对象。
由于无变量名,因此只能使用一次。
package com.leocoder.java;
public class AnonymousobjectTest {
public static void main(String[] args) {
// 1.用法:直接new
new Phone().sendEmail();//发送邮件
new Phone().playGame();//玩游戏
//2.区别:上述两个new其实不是一个实例,用price属性展现
new Phone().price = 1000;
new Phone().showPrice();//0.0,说明和上一个赋值1000的对象不是同一个
//3.开发中的用法
PhoneMall pm = new PhoneMall();
pm.phone(new Phone());//在这里直接new一个匿名对象,正常显示发送邮件,玩游戏
}
}
class PhoneMall{
public void phone(Phone phone){
phone.sendEmail();
phone.playGame();
}
}
class Phone{
double price;
public void sendEmail(){
System.out.println("发送邮件");
}
public void playGame(){
System.out.println("玩游戏");
}
public void showPrice(){
System.out.println(price);
}
}
方法的其他几个方面
1.方法重载
在一个类中,允许存在一个以上的同名方法,只要它们的参数个数或类型不同。
跟方法的权限修饰符、形参名称、方法体的具体内容、返回值是否相同都无关。
一个例子:传入的参数是int,class中只存在double类型的同名方法,就执行此方法:
public class OverloadTest {
public static void main(String[] args) {
OverloadTest test = new OverloadTest();
test.getSum(1,2);//2
//此时会执行未被注释的double类型getSum方法,因为将1、2参数进行自动类型提升
}
// public void getSum(int m, int n){
// System.out.println(1);
// }
public void getSum(double m, double n){
System.out.println(2);
}
}
2.可变个数的形参
允许定义能和多个实参匹配的形参。
具体使用:
- 格式:参数类型 ... 变量名,如:public void show(String ... s)
- 调用时传入的参数个数可以是0个或多个
- 方法中可变形参必须在参数列表末尾,因此最多只能声明一个可变形参。
3.值传递机制
- 如果参数是基本数据类型,此时赋值的是实参所保存的数据值
- 引用数据类型,此时实参赋给形参的是变量所保存的数据的地址值
public class ValueTransferTest {
public static void main(String[] args) {
int m = 10;
int n = 20;
System.out.println("m: "+m + ", n: " + n);//m: 10, n: 20
//形参是基本数据类型,交换不成功
ValueTransferTest test = new ValueTransferTest();
test.swap(m, n);
System.out.println("m: "+m + ", n: " + n);//m: 10, n: 20
//传入引用数据类型,这里是传入一个Data
Data data = new Data();
data.m = 40;
data.n = 50;
System.out.println("m: "+data.m + ", n: " + data.n);//m: 40, n: 50
test.swap(data);
System.out.println("m: "+data.m + ", n: " + data.n);//m: 50, n: 40
}
public void swap(int m, int n){
int temp = m;
m = n;
n = temp;
}
public void swap(Data data){
int temp = data.m;
data.m = data.n;
data.n = temp;
}
}
class Data{
int m;
int n;
}
4.递归
举例:计算n!
public class RecursionTest {
public static void main(String[] args) {
RecursionTest test = new RecursionTest();
System.out.println(test.factorialValue(8));//40320
}
public int factorialValue(int n){
if(n == 0)
return 1;
else{
return n * factorialValue(n-1);
}
}
}
封装与隐蔽
- 问题引入:由于我们需要对部分属性限制某些条件,只能在方法中添加(setXxx);
同时对于属性需要封装。用法:private 类型 属性名。
-
封装性的体现:
- 将属性私有化(private)
- 在类中设置公共方法获取(getXxx)和设置(setXxx)
- 以上两点在本次使用中体现,封装性的体现还有:不对外暴漏私有方法、单例模式
-
Java规定的四种权限(依次增大):private、缺省、protected、public
- 四种权限可以修饰:属性、方法、构造器、内部类
- 修饰class的只能是:public、缺省
| 修饰符 | 类中 | 同一个包内 | 不同包的子类 | 同一个工程中 |
|---|---|---|---|---|
| private | yes | |||
| 缺省 | yes | yes | ||
| protected | yes | yes | yes | |
| public | yes | yes | yes | yes |
构造器constructor
作用:创建对象;初始化对象的信息
说明:
- 如果未显示地定义构造器,系统默认提供一个空参的构造器(即我们平时创建对象是:new + 类名() ,new后的即是构造器 );同时这个默认构造器的权限与类的权限一致
- 构造器定义格式:权限修饰符 类名 (形参列表) {}
- 构造器也可以重载
- 一旦定义了构造器,系统不再提供空参构造器
JaveBean
符合以下标准的java类:
- class是公共的
- 包含空参的公共constructor
- 有属性,且提供get、set方法
this关键字
可以修饰属性、方法、构造器
this理解为:当前对象
在类方法中,可以使用"this.属性"/"this.方法",调用当前对象的属性或方法。但通常省略。
- 不能省略的情况(构造器中同理):方法的形参和属性同名(比如name),想要在方法中(比如setName)设置name的值,必须:this.name = name,其中前一个name是类的属性name,后一个是形参。
- this调用本类中指定的其他的构造器:*this(形参列表) *。构造器不能调用自己(形成了闭环)。
- 构造器调用必须在第一行。
- 构造器内部,最多只能用一个this(形参列表)。
package、import
package:方便对项目中类的管理
- 使用:在源文件的首行进行声明,使用package声明所属的类或接口
- 每"."一次,代表一个文件目录
- 同一个包下,不能定义同名的class
import:
- 在源文件中显示地导入指定包下的某些类、接口
- 在package的声明和class的声明之间import
- 导入多个结构,并列写出即可
- 可以使用import xxx. *,表示导入XXX包下的所有结构
- 如果使用的类/接口是lang包下的,可以省略import
- 如果使用的类/接口是本包下的,不用import
- 如果在某一源文件中,使用了两个个包下的同名类,至少有一个必须以全类名(package名.class名) 的方式显示
- import xxx.*表示,导入xxx包下的所有结构,但不包括xxx包下的子包。如需使用某个包下的子包,仍需显示导入
- import static:导入指定类或接口下的静态结构 (属性、方法)