Java学习笔记 05、面向对象—基本认识(二)

简介: Java学习笔记 05、面向对象—基本认识(二)

五、匿名对象


匿名对象:没有名的实例对象


【1】创建一次性匿名对象


class person{
    public void eat(){
        System.out.println("吃饭啦");
    }
}
public class Main{
    public static void main(String[] args){
        new Person().eat();//匿名对象
    }
}


说明:为什么要叫做匿名对象呢?对象在堆中创建好之后,栈中没有变量指向这个内存空间地址,自然而然下次就无法找到并操作这个对象了。


【2】方法传参匿名参数:


public class Main {
    public static void main(String[] args) throws UnknownHostException {
        //传递匿名参数
        Main.usePerson(new Person());
    }
    public static void usePerson(Person person){
        person.eat();
    }
}
class Person{
    public void eat(){
        System.out.println("吃饭啦");
    }
}


实际上就是将这个内存地址传递给了方法参数中的person来接收,但仅局限在方法中进行使用该对象。一般是我只想调用一次方法并不想额外创建变量名称,就可以使用这种方式传参。



六、值传递与地址传递


概念介绍


方法中的参数叫做形式参数,调用方法进行传参的叫做实际参数。


形式参数:又叫形参,方法定义时,声明的小括号内的参数。

实际参数:又叫实参,实际传递给形参的数据。

方法中传参包含值传递与地址传递


值传递:方法中传递参数为基本数据类型,进行值拷贝

地址传递:方法中传递参数为引用数据类型


实际案例说明

值传递案例


传递内容:基本数据类型int


public class Main {
    public static void main(String[] args) throws UnknownHostException {
        int i = 10;
        int j = 20;
        System.out.println("值传递前:i="+i+" "+"j="+j);//地址传递前:i=10 j=20
        Main.swap(i,j);
        System.out.println("值传递后:i="+i+" "+"j="+j);//地址传递后:i=10 j=20
    }
    //交换i与j值
    public static void swap(int i,int j){
        int sum = i+j;
        i = sum - i;
        j = sum - i;
    }
}


结果:可以看到方法中进行值传递调用前后的值都没有进行交换。


详细说明:


     基本数据类型存放的值称为自动变量,自动变量存储的值是字面值,与在堆中创建类的实例与数组开辟内存空间不同,每当栈中定义了一个自动变量时,会直接赋一个字面值,下一次若定义一个自动变量时会首先去栈中找是否有相同的字面值,若是有直接指向这个字面值。与引用类型引用地址有所不同。


     回到上面代码中,这里是值传递,仅仅是传递字面值(非地址引用),那么在其方法中对i与j操作就与外面操作i与j就无任何关系。所以前后值肯定没有变。



地址传递案例


传递内容:引用数据类型,数组


public class Main {
    public static void main(String[] args){
       int[] arr = {1,2};
       System.out.println("地址传递前:arr[0]="+arr[0]+" "+"arr[1]="+arr[1]);//地址传递前:arr[0]=1 arr[1]=2
       Main.swap(arr,0,1);
       System.out.println("地址传递后:arr[0]="+arr[0]+" "+"arr[1]="+arr[1]);//地址传递后:arr[0]=2 arr[1]=1
    }
    //交换数组arr中下标为i与j的值
    public static void swap(int[] arr,int i,int j){
        int x = arr[i];
        arr[i] = arr[j];
        arr[j] = x;
    }
}


结果:使用地址传递,数组中指定i与j下标位置值发生了调换。


详细说明:


     方法中传递的是引用数据类型,传到形参中的arr中的实际上就是实参arr的引用地址,那么顺理成章形参就能够进行操控这个数组进行指定位置的交换操作,回到main方法中,因为引用的都是相同地址,确确实实进行了交换,那么就如结果一样了。



地址传递(特殊),包装类


传递内容:包装类,为啥说特殊呢,因为传递过去进行交换值,最终结果并不是我所看到的


public static void main(String[] args){
    Integer i = 11;
    Integer j = 12;
    int a = 10;
    System.out.println("地址传递前:i="+i+" "+"j="+j);//地址传递前:i=11 j=12
    Main.swap(i,j);
    System.out.println("地址传递后:i="+i+" "+"j="+j);//地址传递后:i=11 j=12
}
public static void swap(Integer i,Integer j){
    Integer sum = i+j;
    i = sum-i;
    j = sum-i;
}


结果:Integer明明是引用数据类型,最终输出展示却并没有交换。


详细说明:


针对于包装类,首先得知道装箱拆箱,下面直接上例子:


Integer i = 11:将一个字面值直接赋值给Integer包装类,会有装箱操作,其中包含了隐含的操作就是Integer i = Integer.valueOf(11);

int j = i:直接使用上面包装类i给基本类型赋值,会有拆箱的操作,包含隐含的操作就是i.intValue();

     接着我们进行分析方法中的操作,首先第10行,我们将引用数据类型传递给形参i与形参j,当前状态下形参i、j与实参i、j都引用相同的内存地址,接下来注意看下面旁边的注释:


public static void swap(Integer i,Integer j){
    Integer sum = i+j;
    i = sum-i;//隐藏装箱操作:i = Integer.valueOf(sum-i);
    j = sum-i;//隐藏装箱操作:i = Integer.valueOf(sum-i);
}


     这里我们能看到此时形参i与j又进行了不同的内存地址引用,简单说就是它换了个内存地址,并不是说它将以前是实参的引用内存地址中的value值进行更改了。(况且Integer源码中value值为final,常量无法修改)。


Debug:


     说了一堆,我们再进行debug就更加明了,首先我们看下在main方法中包装类i与j的引用地址:



     此时是刚进入到swap方法中,看一下形参i与j的引用地址,发现引用地址与实参的相同,确实是地址传参



     我们执行到第28行,可以看到形参i与j仅仅是引用内存地址发生了改变,此时更加明朗了。



此时我又抛出一个疑问,这个内存地址咋这么眼熟啊,咋Integer包装类相同数值对应的引用内存地址一样呢???


难道是字面值相同,引向同一个地址嘛,不对不对,字面值又没有在堆中开辟空间,又哪里来的内存地址呢,有了这些个疑问,我们点开源码一探究竟,点开Integer的valueOf()方法:



IntegerCache:Integer包装类的静态内部类

Integer.cache:static final Integer cache[];内部类的一个静态常量一维数组,数组会提前存放好对象。下标0开始依次放置-128的包装类到127。

low:static final int low = -128;静态整型常量值为-128。

这里我简单描述一下即可,当调用valueOf()方法时,会先判断传入的int数字是否在**-128-127**之间,如果是的话直接从cache数组中拿即可,若超过范围,就new一个对象出去。


     此时我们解开了为啥内存引用地址与之前相同的疑惑,本来只是想记录一下地址传递的知识点,偶然使用了Integer包装类,偶然发现了自动装箱过程同样是new对象,又偶然发现Integer的缓存数组,让我体会到每个知识点都能够深挖,就看你有没有这个耐心与不断钻研的兴趣。



MVC设计模式

经典MVC模式中,M是指业务模型,V是指用户界面,C则是控制器,使用MVC的目的是将M和V的实现分离。


不同层做的事以及定义的包名:



整个流程:



框架内容介绍:


强制性的使应用程序的输入、处理与输出分开,将MVC应用程序分为三个核心部件:模型、视图、控制器。


最经典的MVC就是JSP+servlet+javaBean,也就是初始阶段学习的javaweb。


JSP相当于view视图(前端视图显示)

servlet相当于controller控制器(获取请求,处理业务)

javabean相当于model(会向数据库查询封装数据到javabean中)

框架包含模式:工厂模式、适配器模式、策略模式等。


常见框架如:ssm(spring,springmvc,mybatis)、ssh(spring,struts,hibernate)、springboot(简化spring与springmvc,提供各种应用场景及启动器)。


简而言之:框架是大智慧,用来对软件设计进行分工;设计模式是小技巧,对具体问题提出解决方案,以提高代码复用率,降低耦合度。


优缺点:


优点:耦合度低、重用性高、部署快、生命周期成本低、可维护性高

缺点:理解MVC复杂、调试困难、不适合小型,中等规模的应用程序、系统结构与实现的复杂度高


参考资料

[1]. Java虚拟机(JVM)的方法区(Method Area)存储了什么内容? 详细信息可查阅博客


[2]. Java基本数据类型与引用数据类型内存分配 对基本数据类型与引用数据类型的产生与内存分配有很好的总结,建议一看


[3]. Integer的自动装箱过程


[4]. 包装类,通过自动装箱后部分对象地址值相同的问题


[5]. 百度百科—MVC设计模式


相关文章
|
12天前
|
Java 关系型数据库 数据库
面向对象设计原则在Java中的实现与案例分析
【10月更文挑战第25天】本文通过Java语言的具体实现和案例分析,详细介绍了面向对象设计的五大核心原则:单一职责原则、开闭原则、里氏替换原则、接口隔离原则和依赖倒置原则。这些原则帮助开发者构建更加灵活、可维护和可扩展的系统,不仅适用于Java,也适用于其他面向对象编程语言。
10 2
|
2月前
|
Java 编译器
封装,继承,多态【Java面向对象知识回顾①】
本文回顾了Java面向对象编程的三大特性:封装、继承和多态。封装通过将数据和方法结合在类中并隐藏实现细节来保护对象状态,继承允许新类扩展现有类的功能,而多态则允许对象在不同情况下表现出不同的行为,这些特性共同提高了代码的复用性、扩展性和灵活性。
封装,继承,多态【Java面向对象知识回顾①】
|
2月前
|
存储 安全 Java
Java修仙之路,十万字吐血整理全网最完整Java学习笔记(基础篇)
从Java环境的搭建到实际代码的编写,从基本用法的讲解到底层原理的剖析,深度解析Java基础知识。本文是《Java学习路线》专栏的起始文章,旨在提供一套完整的Java学习路线,覆盖Java基础知识、数据库、SSM/SpringBoot等框架、Redis/MQ等中间件、设计模式、架构设计、性能调优、源码解读、核心面试题等全面的知识点,并在未来不断更新和完善,帮助Java从业者在更短的时间内成长为高级开发。
Java修仙之路,十万字吐血整理全网最完整Java学习笔记(基础篇)
|
2月前
|
存储 安全 Java
Java修仙之路,十万字吐血整理全网最完整Java学习笔记(进阶篇)
本文是Java基础的进阶篇,对异常、集合、泛型、Java8新特性、I/O流等知识进行深入浅出的介绍,并附有对应的代码示例,重要的地方带有对性能、底层原理、源码的剖析。适合Java初学者。
Java修仙之路,十万字吐血整理全网最完整Java学习笔记(进阶篇)
|
2月前
|
Java
java中面向过程和面向对象区别?
java中面向过程和面向对象区别?
33 4
|
2月前
|
Java
接口和抽象类【Java面向对象知识回顾②】
本文讨论了Java中抽象类和接口的概念与区别。抽象类是不能被实例化的类,可以包含抽象和非抽象方法,常用作其他类的基类。接口是一种纯抽象类型,只包含抽象方法和常量,不能被实例化,且实现接口的类必须实现接口中定义的所有方法。文章还比较了抽象类和接口在实现方式、方法类型、成员变量、构造方法和访问修饰符等方面的不同,并探讨了它们的使用场景。
接口和抽象类【Java面向对象知识回顾②】
|
30天前
|
存储 Java 程序员
Java基础-面向对象
Java基础-面向对象
15 0
|
1月前
|
Java 数据安全/隐私保护
java学习笔记(基础习题)
java学习笔记(基础习题)
31 0
|
1月前
|
Java 程序员 开发工具
java学习笔记
java学习笔记
34 0
|
2月前
|
安全 Java Go
面向对象程序设计语言:Java
Java语言语法和C语言和C++语言很接近,很容易学习和使用,Java丢弃了C++中很少使用的、很难理解的、令人迷惑的特性,Java语言不使用指针,而是引用,并提供了自动分配和回收内存空间,使得程序员不必为内存管理而担忧
55 2
下一篇
无影云桌面