面向对象
一.类与对象
1. 基本介绍:
//1)类是抽象的,概念的,代表一类事物,
//2)对象是具体的,实际的。代表具体的事物,属性的载体,行为的执行者
//3)类是对象的模板,对象是类的一个个体,对应一个实例
2. 如何创建对象
//1. 直接创建:类名 对象名 = new 类名();
//2.先声明在创建 类名 对象名; 对象名 = new ();
// 访问属性 cat.name 对象名.属性名
实例讲解: //养猫问题
//1.先把所有的猫的特性提取出来
//2.猫类:自定义数据类型 int: java提供数据类型 如猫的年龄 大小 行为 **类就是数据类型
//3.猫对象(具体一只猫) 100 200 ** 对象是具体的事物
//定义一个猫类
// 实例化一个猫对象
//1.new Cat() 创建一个猫对象
//2.Cat cat1 = new Cat(); 把创建的猫对象赋给cat1
Cat cat1 = new Cat();
cat1.name = "奶盖";
cat1.age = 18;
cat1.color = "白色";
cat1.weight = 45;
Cat cat2 = new Cat();
cat2.name = "酷盖";
cat2.age = 18;
cat2.color = "黑色";
cat2.weight = 23;
System.out.println("第一只猫的信息 " + cat1.name + " " + cat1.age + " " + cat1.color + " " + cat1.weight);
System.out.println("第二只猫的信息 " + cat2.name + " " + cat2.age + " " + cat2.color + " " + cat2.weight);
class Cat{
//属性
String name; //名字
int age; // 年龄
String color; // 花色
// 可以继续增加信息
int weight;
}
类与对象内存的分配机制:
//Java 内存的结构分析
//1.栈:一般存放基本数据类型
//2.堆:存放对象(Cat cat等)
//3.方法区:常量池(字符串),类加载信息
//简单分析:
//2.Cat cat1 = new Cat(); 把创建的猫对象赋给cat1
Cat cat1 = new Cat();
cat1.name = "奶盖";
cat1.age = 18;
cat1.color = "白色";
//1.先加载Cat信息
//2.堆中分配空间,进行默认初始化
//3.把地址给cat1.cat1指向对象
//4.进行指定初始化
//2.Cat cat1 = new Cat(); 把创建的猫对象赋给cat1
Cat cat1 = new Cat();
cat1.age = 18;
cat2.age = 20; 地址age元素改变
//cat2 = null; // 不能指向地址 出现异常
二 .成员方法
成员方法定义:
public 返回数据类型 方法名(形参列表){
方法体
语句;
return 返回值; // 如果为void没有返回值
}
// ** 编写方法的思路
1.方法的返回类型
2.方法的名字
3.方法的形参
实例引入:
//1)添加speak 成员 输出” 酷盖是大好人“
//1.方法创建好要去调用 2.** 先创建对象 : 调用名+ 创建名 = 对象名.+调用名 3.使用:创建名.方法名();
** Person p1 = new Person();// 创建对象
p1.speak();
输出结果:酷盖是大好人
//2)添加一个cal02的成员 计算1+ 2 + ... + n
p1.cal02( 1000);//在形参列表中输入n的值
class Person{
//1.public 表示方法公开
//2.void 表示没有返回值
//3.speak():speak 表示方法名 ():表示形参列表
public void speak(){
System.out.println("酷盖是大好人");
public void getSum(int a,int b){
int sum = 0;
sum = a + b;
System.out.println("两数之和 = " + sum);
}
}
// ** 方法的调用机制
//首先建立一个main栈 person p1 = new Person() 指向堆里面的对象
//接着执行int return res = p1.getSum() 语句 这时会在栈里创建一个新的独立空间接着分别给a,b赋值 返回res
// 最后res 指向 int return res = p1.getSum(a,b)
//执行完会将独立空间栈释放
// 方法调用小结:
//1.当程序找到方法时会开辟一个新的独立栈空间
//2.当程序执行完毕,或者执行到return语句时就会返回
//3.返回到调用方法的地方
//4.返回后执行下面的代码
//5.当main(栈)执行完毕整个程序退出。
方法的使用细节:
//1.一个方法只能返回一个值 (可以利用数组返回多个值)
Person tool = new Person();
int resArr[] = tool.getSumAndSub(23, 22);
System.out.println("和= " + resArr[0] + "\n" + "差 = " + resArr[1]);
class Person{
public int [] getSumAndSub(int a,int b){
int resArr[] = new int [2] ;
resArr[0] = a + b;
resArr[1] = a - b;
return resArr;
}
}
//2. 返回类型可以为任意类型,基本类型 引用类型 具体见上
//3.如果方法中需要返回值 需要保证返回数据类型与return数据类型相同或兼容 && 形参也一样
//public int arr(){
double a = 1.1 * 5;
return a; // 不行 double不能到int
public double arr(){
int a = 1* 5;
return a; // 行 int 可以到 double
//4.如果为 void 不加return 返回值 或者直接写return
//5.同一个类的方法直接调用就可以
//6.跨类使用需要先创建对象在调用
B p1 = new B();
p1.f3();
class A{
public void f1(){
System.out.println("你好,奶盖");
}
public void f2(){
f1(); // 直接使用
System.out.println("好久不见");
}
}
class B{
public void f3(){
A p2 = new A(); // 跨类使用
p2.f2();
System.out.println("酷盖");
}
}
方法的传参机制 重点
// 1. 基本数据类型的传参机制
AA a = new AA();
int n1 = 22;
int n2 = 23;
a.swap(n1,n2); //输出结果 22 23 和 23 22
System.out.println("交换后 n1 和 n2 的值"+ " " + "n1 = " + n1 +" "+ "n2 = " + n2); //a = 22 b = 23
}
}
class AA{
public void swap(int a,int b){
System.out.println("交换前 a 和 b 的值"+ " " + "a = " + a +" "+ "b = " + b);
int tmp;
tmp = a;
a = b;
b = tmp;
System.out.println("交换后 a 和 b 的值"+ " " + "a = " + a +" "+ "b = " + b);
}
}
// 分析:
//1.栈中 有个main栈 其中 a = 23,b = 22
//1.当执行 a.swap(a,b); 开辟一个独立空间 swap 栈
//3.其中a,b值互换 但是swap栈 和main 栈互不影响 其中变量不改变彼此
//4.所以swap栈中a,b值互换 main栈中a,b值不变
// 总结:** 基本数据类型传递的值是(值拷贝),形参的改变不影响实参(main)
// 2.引用数据类型的传参机制
int arr[] = {1,2,3};
B b = new B();
b.test(arr);
System.out.println("main 中的数组元素");
for(int i = 0; i <arr.length;i++) {
System.out.print(arr[i] + " ");
}
System.out.println(); // 输出结果:23 2 3
class B{
public void test(int Arr []){
Arr [0] = 23;
System.out.println("test 中的数组元素");
for(int i = 0; i <Arr.length;i++) {
System.out.print(Arr[i] + " ");
}
System.out.println();
}
}
//分析: 重点 数组是引用数据类型,传递的是地址 指向堆
//1.执行到int arr[] = {1,2,3}; arr->堆里的地址,地址中存放arr{1,2,3}元素
//2.执行到 b.test(arr);开辟一个test栈,其中数组也是指向堆中数组元素的相同地址
//3.执行到Arr [0] = 23; 改变地址中arr[0]的元素
//4.最后在中执行System.out.print(arr[i] + " ");也是指向那个地址,所以数组元素改变
//总结:** 引用传递类型传递的是地址,可以通过形参形象实参
// 对象传递也是引用类型 通过方法会改变属性
Person p1 = new Person();
p1.age = 18;
System.out.println("年龄是 = " + p1.age);
A a = new A();
a.test100(p1);
System.out.println("年龄是 = " + p1.age);
}
}
class Person{
int age;
}
class A{
public void test100(Person p1) { //形参写类名 + 对象名
// p1.age = 20;
// p1 = null; // 结果是18; // 不在指向堆中的地址
p1 = new Person(); // 在堆中在创建一个对象 不在指向原来的对象 该对象会被回收
p1.age =20; // 输出18;
}
}
克隆对象://copyPerson 一个对象 但两个对象是独立空间
Person p1 = new Person();
p1.name = "奶盖";
p1.age = 18;
MyTool tool = new MyTool();
Person p2 = tool.copyPerson(p1);
System.out.println("p1名字信息分别为" + " " + p1.name + " " + p1.age);
System.out.println("p2名字信息分别为" + " " + p2.name + " " + p2.age);
//判断是不是同一个地址
System.out.println(p1 == p2);//false代表不是同一个地址
//p1 p2 是person的对象但这两个是独立的对象,属性相同
}
}
class Person{
String name;
int age;
}
class MyTool{
// ** 编写方法的思路
//1.方法的返回类型
//2.方法的名字
//3.方法的形参
//4.方法体 创建一个对象 复制并返回
public Person copyPerson(Person p1){
//创建一个新对象
Person p2 = new Person();
p2.name = p1.name;;
p2.age = p1.age;
return p2;
}
}
三.重载
//基本介绍:同一个类中,相同的方法名, 形参列表不同
//减轻了起名和记名的麻烦,
//重载细节:
//1.方法名必须相同
//2.形参类型:必须不同,或者顺序不同 至少有一个不同
//3.返回类型无要求 如果两个方法只是返回类型不同 则不能构成重载
class MyCalculator{
public int calculator(int n1,int n2){
return n1+n2;
}
public double calculator(int n1,double n2){
return n1+n2;
}
public int calculator(int n1,int n2,int n3){
return n1+n2+n3;
}
}
class Methods1{
public void max(int n1,int n2){
if (n1 > n2){
System.out.println(n1);
}else{
System.out.println(n2);
}
}
public void max(double n1,double n2){
if (n1 > n2){
System.out.println(n1);
}else{
System.out.println(n2);
}
}
public double max(double n1,double n2,double n3){
double max1 = n1 > n2 ? n1:n2;
return max1 > n3 ? max1 : n3;
}
四.作用域
作用域:
//1.主要的变量是属性(成员变量)和局部变量
//2.局部变量一般为成员方法中定义的变量(cat类)
//3.全局变量:作用域为整个类体 Cat类(cry,eat)
//4.全局变量可以不赋值使用,但是局部变量必须赋值后使用
Cat c = new Cat();
c.cry();
c.eat();
class Cat{
int age = 18;
// int age ; 全局变量 可以不赋值 结果为默认值
public void cry(){
String name = "奶盖";
System.out.println("在cry中 age = " + age);
int num; // 局部变量不可以不赋值否则会报错
// System.out.println(num);
}
public void eat(){
String name = "酷盖";
System.out.println("在eat中 age = " + age);
}
}
作用域的使用细节:
//1.属性可以和局部变量重名,访问时遵守就近原则
//2.同一个作用域中,比如同一个方法中,两个局部变量不能重名
//3.属性的生命周期较长,伴随对象的创建而创建,销毁而销毁。局部变量,生命周期较短,伴随代码块的执行而创建,结束而销毁
//4.作用域范围不同 全局变量:可以被本类方法使用 也可以被其他类方法使用 局部变量: 只能被本类方法使用
//5.属性可以加修饰符 但是局部变量不能加修饰符
五.构造器
//基本介绍:是类的一种特殊方法,主要作用是完成对新对象的初始化
// 基本语法:
//修饰符 方法名(形参列表){
// 方法体 }
//1.构造器修饰符可以默认
//2.构造器没有返回值
//3.方法名和类名要相同
//4.创建对象时,系统会自动的调用该类的构造器对其进行初始化
Person p1 = new Person("酷盖",18);
Person p2 = new Person("奶盖",18);
System.out.println("p1的信息如下" + " name " + p1.name + " " + " age " + p1.age);
System.out.println("p2的信息如下" + " name " + p2.name + " " + " age " + p2.age);
}
}
class Person{
String name;
int age;
public Person(String pName , int page){
name = pName;
age = page;
}
}
构造器使用细节:
//1.一个类可以定义多个构造器,即构造器的重载
//2.构造器没有返回值
//3.方法名和类名要相同
//4.构造器是完成对象的初始化,并不是创建对象
//5.在创建对象时,系统自动调用该类的构造方法
//6.当定义构造器的时候默认构造器被覆盖不能使用,需要定义一下默认构造器 例如 Person(){}
// 对象创建的流程分析
Person p = new Person(18,"奶盖");
System.out.println(p.age + p.name);
class Person{
int age = 18;
String name;
public Person(int a ,String n){
age = a;
name = n;
}
分析:1.加载person类信息,只会加载一次
2.在堆中完成分配空间(地址)
3.完成对象的初始化(默认初始化->显式初始化->构造器的初始化)
4.对象在堆中的地址返回给p