Java面向对象编程——part1类与对象
本文是学习韩顺平老师Java课程时整理的学习笔记,内容为个人理解与总结,如有错误欢迎指正。
类与对象(OOP)
类(自定义数据类型):猫的所有属性(name, age, color)和行为(run, cry, eat)
int是java提供的数据类型,对象值是100,200;
对象(实例):具体一只猫,创建对象(一个具体的实例)
int a = 100;
Cat c1 = new Cat();
类是抽象的概念的,是数据类型;对象是具体的实际的实例;类是对象的模板,对象是类的一个个体;
class Cat{ //定义一个类Cat,有哪些属性(成员变量)
String name;
int age;
String color;
}
public class OopTest01 {
public static void main(String[] args) {
Cat cat1 = new Cat(); //创建一个对象new Cat(),对象名是cat1
cat1.name = "小白";
cat1.age = 3;
cat1.color = "白色";
Cat cat2 = new Cat(); //创建一个对象
cat2.name = "小花";
cat2.age = 10;
cat2.color = "花色";
//访问对象的属性
System.out.println("第二只猫的信息" + cat2.name + " "
+ cat2.age + " "+ cat2.color);
}
}
类的内存形式
class类和String和数组一样,都是引用数据类型

属性 = 成员变量 ,对象的属性有默认值
class Car{ //定义一个类Car
protected String name; //访问修饰符+属性类型+属性名
double price;
String color;
String[] owner; //可以是基本数据类型,引用数据类型
}
Car c1;
c1 = new Car(); //先声明再创建对象
Car c2 = new Car(); //直接创建
c1.price; //访问对象的属性
类和对象的内存分配机制
栈:存放局部变量,基本数据类型的值(a=10),引用类型的地址(数组arr的地址,对象p1的地址)
堆:存放new产生的对象(对象具体的值,数组的值)
方法区:常量池(如String的值”小明”),类加载信息

int a = 10;
int[] arr = new int[5];
//Person类包含名字,年龄
Person p1 = new Person();
//在方法区加载Person类信息,在堆中创建对象分配空间默认初始值
//在栈中创建引用变量p1,保存对象的地址
p1.age = 10;
p1.name = "小明";
Person p2 = p1; //引用赋值,指向同一个对象
class Person{
String name;
int age;
}
创建成员方法
类 = 属性(成员变量)+ 行为(成员方法),成员方法简称方法
/*
访问修饰符 返回数据类型 方法名(形参列表){ //方法体
语句;
return 返回值; //可以没有返回,void时return后不能有值
} */
//最多只有一个返回值(可以是数组),返回数据类型和return的值类型一致或兼容
public int[] getNum(int n1, int n2){
int[] res = new int[2];
res[0] = n1 + n2;
res[1] = n1 - n2;
return res;
}
方法可以多次调用,形参列表是方法的输入,方法体实现功能的代码块;
访问修饰符(作用是控制方法/属性的使用范围)有四种public,protected,包访问(默认),private;
同一个类中的方法调用:直接调用;跨类通过对象名调用;
public class Method01 {
public static void main(String[] args) {
Person p1 = new Person(); //创建对象
p1.age = 10;
p1.name = "小明";
p1.speak(); //调用方法
p1.cal01(10); //调用方法,n=10
int a = p1.getSum(10,20); //调用方法n1=10,n2=20,返回值赋给a
System.out.println("返回值" + a);
}
}
class Person{ //Person类的属性name,age,方法speak,cal01,getSum
String name;
int age;
//添加speak方法:public表示方法是公开的,void表示方法没有返回值
//speak是方法名,()是形参列表,{}是方法体-具体要做的事
public void speak(){
System.out.println("我是一个好人");
}
//n是形参,可以接收用户输入
public void cal01(int n){
int sum = 0;
for(int i = 1; i <= n; i++){
sum += i;
}
System.out.println("sum=" + sum);
}
//int表示方法有int类型的返回值,两个形参,返回res的值return跳出方法
public int getSum(int n1,int n2){
int res = n1 + n2;
return res;
}
}
**方法的调用机制**(getSum案例)非常重要!!
(图的一个小问题是main栈应该在下面,getSum栈空间在上面)

1、Method01和Person类信息加载进方法区(方法如何执行);
2、创建main方法的栈空间,在main栈执行语句new Person()在堆中创建对象,分配0x0011地址空间,成员变量赋默认值,并在main栈中创建局部变量p1,保存0x0011地址指向堆中的对象;
3、执行age和name赋值,10在堆中修改,name通过地址引用指向常量池中“小明”;
4、在main栈执行getSum方法调用语句,创建getSum栈空间,放入n1=10, n2=20,在getSum栈空间执行方法体得到res=30,并将值返回给main栈空间中的变量a=30,return后getSum栈空间立即销毁;
5、执行System.out输出,main方法结束,程序退出,然后main栈空间销毁,堆中的Person对象失去地址引用,成为可回收对象;
public class Method01 {
public static void main(String[] args) {
Person p1 = new Person();
p1.age = 10;
p1.name = "小明";
int a = p1.getSum(10,20);
System.out.println("返回值" + a);
}
}
class Person{
String name;
int age;
public int getSum(int n1,int n2){
int res = n1 + n2;
return res;
}
}
方法的传参机制
基本数据类型,传递的是值(值拷贝),形参的任何改变不影响实参;
引用数据类型,传递的是地址,形参的改变影响实参;(类是引用数据类型)
public class Method03 {
public static void main(String[] args) {
Person p = new Person();
p.name = "jack";
p.age = 10;
B b = new B();
b.test2(p); //p的值是一个地址,指向Person对象
System.out.println("main的p.age=" + p.age); //=100
}
}
class Person{
String name;
int age;
}
class B{
public void test2(Person p){ //test2方法传入一个地址p(数据类型是Person)
p.age = 100; //根据地址修改属性的值
}
}
递归调用
执行一个方法时,就创建一个新的栈空间;谁调用结果返回给谁;
public class Recursion01 {
public static void main(String[] args) {
T t1 = new T();
t1.test01(4); //每个递归创建新栈,返回输出n=2,n=3,n=4
int res = t1.factorial(5);
System.out.println("res=" + res);
}
}
class T{
public void test01(int n){ //递归案例1
if(n > 2){
test01(n - 1);
}
System.out.println("n=" + n);
}
public int factorial(int n){ //递归案例2-阶乘
if(n == 1){
return 1;
}else{
return factorial(n - 1) * n; //向上递归生成栈,向下返回值
}
}
}
方法重载Overload
同一个类中,允许同名方法存在,但要求形参列表不同,类型/顺序/个数不同;
形参名不同/返回值类型不同不能构成重载,会报错;
class Overload{
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){
retrun n1 + n2;
}
}
可变参数
java可以将同一个类中多个同名同功能但参数个数不同的方法,封装成一个方法,通过可变参数实现,接收任意个参数;(不常用)
public int sum(int... nums) { //n个数的和,0-多个,nums当成数组
int res = 0;
for(int i = 0; i < nums.length; i++){
res += nums[i];
}
return res;
}
作用域
变量:全局变量(属性(成员变量))和局部变量(成员方法和代码块定义的)
局部变量的作用域只在对应方法中,全局变量(属性)作用域是整个类
public class VarScope {
public static void main(String[] args) {
Person p1 = new Person();
Cat c1 = new Cat();
c1.test2(p1);
}
}
class Cat{
int age = 10; //全局变量
public void cry(){
int n = 1;
String name = "jack"; //局部变量
}
public void test2(Person p){ //跨类调用
System.out.println(p.name);
}
}
class Person{
String name = "jack";
}
全局变量(属性)可以不赋值,有默认值;局部变量必须赋值,没有默认值;
全局和局部变量可以重名,就近访问;
全局变量也可以被其他类通过对象调用;
全局变量可以加修饰符,局部变量不可以;
构造器
构造器是类的一种特殊方法,实现对新对象的初始化
构造器没有返回值,方法名和类名相同(后面用this写)
public class Constructor01 {
public static void main(String[] args) {
//new创建对象时,可以通过构造器初始化属性的值
Person p1 = new Person("smith",80);
}
}
class Person{
String name;
int age;
public Person(String pname, int page){
System.out.println("构造器被调用");
name = pname;
age = page;
}
}
一个类可以有多个构造器(重载)
若没有定义构造器,系统会自动生成默认无参构造器
对象创建的流程分析(含构造器)
1、方法区加载Person类信息,只会加载一次;
2、堆中创建对象分配空间(地址);
3、对象初始化:首先默认初始化0,然后显式初始化(类的属性有赋值),最后构造器的初始化;
4、对象在堆中的地址返回给p;
class Person{
String name;
int age = 90; //堆中age的值变化:0-90-20
Person(String n, int a){
name = n;
age = a;
}
}
Person p = new Person("小倩",20); //简化(实际写在main中)
this关键字
前面的构造器都要用新的变量接收初始化的值,变成this.age = age;
哪个对象调用,this就代表哪个对象;

class Dog{
String name;
int age;
public Dog(String name, int age){
this.name = name; //表示当前对象的属性
this.age = age;
}
}
Dog dog1 = new Dog("大壮", 3); //简化(实际写在main中)
Dog dog2 = new Dog("大黄", 2);
//案例
public class this01 {
public static void main(String[] args) {
//通过构造器进行对象初始化
Person p1 = new Person("jack", 20);
Person p2 = new Person("smith", 30);
System.out.println("p1和p2比较结果" + p1.compareTo(p2)); //false
//this代表调用对象p1,p代表传入的p2
}
}
class Person{
String name;
int age;
public Person(String name, int age){
this.name = name;
this.age = age;
}
public boolean compareTo(Person p){
return this.name.equals(p.name) && this.age == p.age;
}
}
this可以访问本类的属性,方法,构造器;
this能够区分全局变量(属性)和局部变量this.age = age;
class T {
//两个构造器
public T(){
this("jack", 10); //this只能在一个构造器中访问另一个构造器
System.out.println("无参构造器");
}
public T(String name, int age){
System.out.println("有参构造器");
}
//两个方法
public void f1(){
System.out.println("f1()方法");
}
public void f2(){
System.out.println("f2()方法");
f1(); //两种方式都可以访问f1方法
this.f1(); //this访问f1方法
}
}
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐


所有评论(0)