精华内容
下载资源
问答
  • Java参数传递方式

    千次阅读 2014-10-25 09:49:28
    Java参数传递方式分为基本类型参数传递和对象类型参数传递。

    原文:http://blog.sina.com.cn/s/blog_59ca2c2a0100qhjx.html,我作了些修改并增加了一个实例,增加对比

    本文通过内存模型的方式来讨论一下Java中的参数传递。


    1、基本类型参数的传递方式

    这里的内存模型涉及到两种类型的内存:栈内存(stack)和堆内存(heap)。基本类型作为参数传递时,传递的是这个值的拷贝。无论你怎么改变这个拷贝,原值是不会改变的。看下边的一段代码,然后结合内存模型来说明问题:

    public class ParameterTransfer {
     public static void main(String[] args) {
      int num = 30;
      System.out.println("调用add方法前num=" + num);
      add(num);
      System.out.println("调用add方法后num=" + num);
     }
     
     public static void add(int param) {
      param = 100;
     }
     
    }
    这段代码运行的结果如下:
    调用add方法前num=30
    调用add方法后num=30
        

    程序运行的结果也说明这一点,无论你在add()方法中怎么改变参数param的值,原值num都不会改变。
    下边通过内存模型来分析一下。
    当执行了int num = 30;这句代码后,程序在栈内存中开辟了一块地址为AD8500的内存,里边放的值是30,内存模型如下图:


     执行到add()方法时,程序在栈内存中又开辟了一块地址为AD8600的内存,将num的值30传递进来,此时这块内存里边放的值是30,执行param = 100;后,AD8600中的值变成了100。内存模型如下图:   


    地址AD8600中用于存放param的值,和存放num的内存没有任何关系,无论你怎么改变param的值,实际改变的是地址为AD8600的内存中的值,而AD8500中的值并未改变,所以num的值也就没有改变。

    2、对象类型参数的传递方式

    1)先看下边的示例代码:

    public class ParameterTransfer {
     public static void main(String[] args) {
      String[] array = new String[] {"huixin"};
      System.out.println("调用reset方法前array中的第0个元素的值是:" + array[0]);
      reset(array);
      System.out.println("调用reset方法后array中的第0个元素的值是:" + array[0]);
     }
     
     public static void reset(String[] param) {
      param[0] = "hello, world!";
     }
     
    }
    运行的结果如下:
    调用reset方法前array中的第0个元素的值是:huixin
    调用reset方法后array中的第0个元素的值是:hello, world!
    当对象作为参数传递时,传递的是对象的引用,也就是对象的地址。下边用内存模型图来说明。


    当程序执行了String[] array = new String[] {"huixin"}后,程序在栈内存中开辟了一块地址编号为AD9500内存空间,用于存放array[0]的引用地址,里边放的值是堆内存中的一个地址,示例中的值为BE2500,可以理解为有一个指针指向了堆内存中的编号为BE2500的地址。堆内存中编号为BE2500的这个地址中存放的才是array[0]的值:huixin。
    当程序进入reset方法后,将array的值,也就是对象的引用BE2500传了进来。这时,程序在栈内存中又开辟了一块编号为AD9600的内存空间,里边放的值是传递过来的值,即AD9600。可以理解为栈内存中的编号为AD9600的内存中有一个指针,也指向了堆内存中编号为BE2500的内存地址,如图所示:


    这样一来,栈内存AD9500和AD9600(即array[0]和param的值)都指向了编号为BE2500的堆内存。
    在reset方法中将param的值修改为hello, world!后,内存模型如下图所示:


    改变对象param的值实际上是改变param这个栈内存所指向的堆内存中的值。param这个对象在栈内存中的地址是AD9600,里边存放的值是BE2500,所以堆内存BE2500中的值就变成了hello,world!。程序放回main方法之后,堆内存BE2500中的值仍然为hello,world!,main方法中array[0]的值时,从栈内存中找到array[0]的值是BE2500,然后去堆内存中找编号为BE2500的内存,里边的值是hello,world!。所以main方法中打印出来的值就变成了hello,world!

    2)我们再来看个例子

    class Dog{
    	int x,y;
    	int z=1;
    	Dog(int x,int y){
    		this.x=x;
    		this.y=y;
    	}
    	void move1(Dog d){
    		d.x=d.x+10;
    		d.y=d.y+10;
    	}
    	void move2(Dog d){
    		Dog d2=new Dog(100, 100);
    		d=d2;
    		
    	}
    }
    public class UseDog {
    
    	public static void main(String[] args) {
    		// TODO Auto-generated method stub
    		Dog d1=new Dog(10,10);
    		d1.move2(d1);
    		System.out.print(d1.x+","+d1.y+":");
    		d1.move1(d1);
    		System.out.println(d1.x+","+d1.y+";");
    	}
    
    }
    输出结果为:10,10:20,20;

    先解释10,10:当执行d1.move2(d1)时,d1(引用地址)传入move2中,栈内存开辟空间存入。之后新建对象d2,并将d2(引用地址)赋给d,那么d就指向了对象d2。因此并未改变d1所指向的堆内存值。

    再解释20,20:当执行d1.move1(d1)时,d1(引用地址)传入move1中,栈内存开辟空间存入,即d指向了d1所指向的堆内存值。这时在move1中改变d所指向的对象的值,那么d1所指向的对象值也改变了。因为d和d1指向的是同一个对象。


    3、总结

    无论是基本类型作为参数传递,还是对象作为参数传递,实际上传递的都是值,只是值的的形式不用而已。第一个示例中用基本类型作为参数传递时,将栈内存中的值30传递到了add方法中。第二个示例中用对象作为参数传递时,将栈内存中的值BE2500传递到了reset方法中。当用对象作为参数传递时,真正的值是放在堆内存中的,传递的是栈内存中的值,而栈内存中存放的是堆内存的地址,所以传递的就是堆内存的地址。这就是它们的区别。

    补充一下,在Java中,String是一个引用类型,但是在作为参数传递的时候表现出来的却是基本类型的特性,即在方法中改变了String类型的变量的值后,不会影响方法外的String变量的值。关于这个问题,可以参考如下两个地址:
    http://freej.blog.51cto.com/235241/168676
    http://dryr.blog.163.com/blog/static/58211013200802393317600/
    我觉得是这两篇文章中提到的两个原因导致的,一个是String实际上操作的是char[],可以理解为String是char[]的包装类。二是给String变量重新赋值后,实际上没有改变这个变量的值,而是重新new了一个String对象,改变了新对象的值,所以原来的String变量的值并没有改变。

    展开全文
  • C/C++中语言的3种参数传递方式

    万次阅读 多人点赞 2017-09-14 18:30:26
    参数传递,是在程序运行过程中,实际参数就会将参数值传递给相应的形式参数,然后在函数中实现对数据处理和返回的过程,方法有3种方式 值传递 地址传递 引用传递 tips: 被调用函数的形参只有函数被调用时才会临时...

    参数传递,是在程序运行过程中,实际参数就会将参数值传递给相应的形式参数,然后在函数中实现对数据处理和返回的过程,方法有3种方式

    • 值传递
    • 地址传递
    • 引用传递

    ##tips:

    1. 被调用函数的形参只有函数被调用时才会临时分配存储单元,一旦调用结束占用的内存便会被释放
    2. 值传递和地址传递,传递的都是实参的一个拷贝
    3. C语言中实参和形参之间的数据传递是单向的“值传递”,单向传递,只能由实参传给形参,反之不行
    4. 输出格式并没有选择%p而是选择了%d,因为十进制的数看起来更直观

    ##值传递

    • 如果只是传递值的话:
    #include <stdio.h>
        //值传递传值
    void swap( int x, int y);
    int main()
    {
    	int a=2,b=3;
    	printf("before:实参为a,b\na=%d,地址为%d\nb=%d,地址为%d\n\n",a,&a,b,&b);
    	swap(a,b);
    	printf("after:实参为a,b\na=%d,地址为%d\nb=%d,地址为%d\n\n",a,&a,b,&b);
    	return 0;
    }
    void swap(int x,int y)
    {
    	int tmp;
    	tmp=x;
    	x=y;
    	y=tmp;
        printf("inside:形参为x,y\nx=%d,地址为%d\ny=%d,地址为%d\n\n",x,&x,y,&y);
    }
    

    执行结果:
    值传递_值

    • 如果传递的是地址呢?
    #include <stdio.h>
        //值传递传地址
    void swap( int *x, int *y);
    int main()
    {
    	int a=2,b=3;
    	printf("before:实参为&a,&b\na=%d,地址为%d\nb=%d,地址为%d\n\n",a,&a,b,&b);
    	swap(&a,&b);
    	printf("after:实参为&a,&b\na=%d,地址为%d\nb=%d,地址为%d\n\n",a,&a,b,&b);
    	return 0;
    }
    void swap(int *x,int *y)
    {
    	int *tmp= NULL;
    	tmp=x;
    	x=y;
    	y=tmp;
        	printf("inside:形参为*x,*y\n*x=%d,x=%d,地址为%d\n*y=%d,y=%d,地址为%d\n\n",*x,x,&x,*y,y,&y);
    }
    

    执行结果:
    值传递_地址

    ##地址传递

    #include <stdio.h>
        //地址传递
    void swap( int *x, int *y);
    int main()
    {
    	int a=2,b=3;
    	printf("before:实参为&a,&b\na=%d,地址为%d\nb=%d,地址为%d\n\n",a,&a,b,&b);
    	swap(&a,&b);
    	printf("after:实参为&a,&b\na=%d,地址为%d\nb=%d,地址为%d\n\n",a,&a,b,&b);
    	return 0;
    }
    void swap(int *x,int *y)
    {
    	int tmp;
    	tmp=*x;
    	*x=*y;
    	*y=tmp;
        	printf("inside:形参为*x,*y\n*x=%d,x=%d,地址为%d\n*y=%d,y=%d,地址为%d\n\n",*x,x,&x,*y,y,&y);
    }
    

    执行结果为:
    地址传递

    ##引用传递

    #include <stdio.h>
        //引用传递
    void swap( int &x, int &y);
    int main()
    {
    	int a=2,b=3;
    	printf("before:实参为a,b\na=%d,地址为%d\nb=%d,地址为%d\n\n",a,&a,b,&b);
    	swap(a,b);
    	printf("after:实参为a,b\na=%d,地址为%d\nb=%d,地址为%d\n\n",a,&a,b,&b);
    	return 0;
    }
    void swap(int &x,int &y)
    {
    	int tmp;
    	tmp=x;
    	x=y;
    	y=tmp;
        	printf("inside:形参为&x,&y\nx=%d,地址为%d\ny=%d,地址为%d\n\n",x,&x,y,&y);
    }
    

    执行结果为:
    引用传递

    ##补充

    int x=1;
    int *y=&x; //用于指针传递,y有自己独立的内存地址,存储的内容是x的地址,*y是x的值
    int &z=x; //用于引用传递,可以理解为z就是x,x就是z,只不过名字不一样
    
    展开全文
  • SpringBoot前后端分离参数传递方式总结

    千次阅读 多人点赞 2020-11-26 21:39:50
    因为总是需要使用不同的参数传递方式,所以特地来总结一下SpringBoot中常用的传递参数的方式。 SpringBoot参数传递 注意:虽然Restful风格很流行,但是大部分还是主要是GET和POST的内容,所以这里只是列举GET和POST...

    前言: 因为总是需要使用不同的参数传递方式,所以特地来总结一下SpringBoot中常用的参数的绑定方式,给有需要的朋友查阅。

    SpringBoot参数传递

    在这里插入图片描述

    注意:虽然Restful风格很流行,但是大部分还是主要是GET和POST的内容,所以这里只是列举GET和POST请求为例。 而且,无论怎么样的花样传参,它都是符合上面这个报文结构的!正所谓:万变不离其宗嘛!

    GET请求方式

    注意:我这里是示例形式是:代码+Postman测试截图+Fiddler抓包截图。

    01.单个键值对参数

    /**
     * GET 方式传递参数  单个参数
     * */
    @GetMapping("/get01")
    public String get01(String comment) {
    	return comment == null ? "no parameter" : comment;
    }
    

    请求不带参数
    在这里插入图片描述

    请求报文中也没有数据,响应报文体中有数据
    在这里插入图片描述

    请求带参数
    在这里插入图片描述

    请求携带数据,数据在请求行中,注意数据被编码了
    在这里插入图片描述

    使用了@RequestParam注解,请求必须携带参数,否则就会报错,否则就是:错误码400 Bad Request

    @GetMapping("/get02")
    public String get02(@RequestParam("comment") String comment) {
    	return comment;
    }
    

    请求不携带参数,请求错误 400 Bad Reqeust
    在这里插入图片描述

    请求携带参数,接收成功
    在这里插入图片描述
    请求和响应报文
    在这里插入图片描述

    如果参数不添加 @RequestParam 注解,那么这个参数即可不传递,而使用了注解的话,默认是必须传递参数的,当然了也可以配置为false。但是,我倾向于还是显示使用注解,这样比较清晰,也可配置,更加灵活。

    在这里插入图片描述

    02.多个键值对参数

    /**
     * GET 方式传递参数  多个参数
     * */
    @GetMapping("/get03")
    public String get03(@RequestParam("id") String id,
    		@RequestParam("name") String name,
    		@RequestParam("comment") String comment) {
    	System.out.println(id + " " + name + " " + comment);		
    	return id + " " + name + " " + comment;
    }
    

    请求行携带多个参数
    在这里插入图片描述

    请求和响应报文
    在这里插入图片描述

    03.键值对映射对象

    /**
     *  使用对象对参数进行封装,这样在多个参数时,优势很明显。
     *  但是这里无法使用 @RequestParam注解,否则会出错。
     * */
    @GetMapping("/get04")
    public Comment get04(Comment comment) {
    	if (Objects.isNull(comment)) {
    		return null;  // 需要对 null 值进行处理
    	}
    	System.out.println(comment);
    	return comment;
    }
    

    请求携带多个参数,直接映射成对象,但是这里无法使用@RequestParam,同时也无法使用@RequestBody,因为参数不在请求体中,至于为什么无法使用,暂时还没明白!
    在这里插入图片描述

    请求和响应报文
    在这里插入图片描述

    因为没有使用注解,可以不携带参数
    在这里插入图片描述

    04.键值对映射Map

    /**
      * 使用对象封装参数要求必须具有一个对象,所以可以使用 Map 来封装,这样可以减少对象的数
      * 量。 
      * * */
    @GetMapping("/get05")
    public Map<String, String> get05(@RequestParam Map<String, String> map) {
    	map.forEach((k, v) -> {
    		System.out.println(k + " --> " + v);
    	});
    	System.out.println(map.size());
    	return map;
    }
    

    在这里插入图片描述

    多个键值对参数
    在这里插入图片描述

    请求和响应报文
    在这里插入图片描述

    05.路径参数

    /**
     * 参数和路径结合,适用于单个参数的情况
     * */
    @GetMapping("/get06/{id}")
    public Comment getById(@PathVariable("id") String id) {
    	Comment comment = new Comment();
    	comment.setId(id);
    	comment.setName("Alfred");
    	comment.setComment("I love you yesterday and today!");
    	return comment;
    }
    

    请求直接写在路径上,成为路径的一部分
    在这里插入图片描述

    请求和响应体

    注: 请求参数就在路径上面。
    在这里插入图片描述
    在这里插入图片描述

    06.返回值为二进制

    前面都是文本数据,现在我们尝试来获取二进制数据,注意这个方法需要下面的上传文件方法向上传文件,或者你自己在文件夹下面放入一个文件。

    /**
     * 返回值为二进制
     * 其实这里可以使用 Files.readAllBytes()这个方法,这样就简单了。这里我就不改了,我习惯了使用这种
     * 循环读取的方式,不过确实有点繁琐了。
     * */
    @GetMapping("/get07/{name}")
    public void getFile(@PathVariable("name") String name, HttpServletResponse response) {
    	try (OutputStream out = new BufferedOutputStream(response.getOutputStream())) {
    		try (InputStream in = new BufferedInputStream(new FileInputStream(new File(baseDir, name)))) {
    			int len = 0;
    			byte[] data = new byte[4*1024];
    			while ((len = in.read(data)) != -1) {
    				out.write(data, 0, len);
    			}
    		}
    	} catch (IOException e) {
    		e.printStackTrace();
    	}
    }
    

    响应体中含有图片的数据
    在这里插入图片描述

    请求体报文
    在这里插入图片描述

    响应报文,注意图片的二进制数据无法解码,会显示出乱码的效果
    在这里插入图片描述

    使用ImageView的方式查看图片
    在这里插入图片描述

    POST请求方式

    01.多个键值对参数

    /**
     * POST方式传递参数
     * @return 
     * */
    @PostMapping("/post01")
    public String post01(@RequestParam("id") String id,
    		@RequestParam("name") String name,
    		@RequestParam("comment") String comment) {
    	System.out.println(id + " " + name + " " + comment);		
    	return id + " " + name + " " + comment;
    }
    

    请求体中携带键值对参数,注意Content-Type类型
    在这里插入图片描述

    请求参数以键值对的形式放在请求体中,注意它也是被编码的
    在这里插入图片描述

    请求体中携带键值对参数,注意Content-Type类型为form-data

    在这里插入图片描述

    请求体中的数据以表单数据的形式存放,注意其形式
    在这里插入图片描述

    02.键值对映射Map

    @PostMapping("/post02")
    public Map<String, String> post02(@RequestParam Map<String, String> map) {
    	map.forEach((k, v) -> {
    		System.out.println(k + " --> " + v);
    	});
    	return map;
    }
    

    Content-Type选择:form-data
    在这里插入图片描述

    在这里插入图片描述

    Content-Type选择:x-www-form-urlencoded

    在这里插入图片描述

    在这里插入图片描述

    03.传递json数据映射对象

    @PostMapping("/post03")
    public Comment post03(@RequestBody Comment comment) {
    	System.out.println(comment);
    	return comment;
    }
    

    请求参数形式为json字符串,并且选择Content-Type选择 raw,不能选择其它形式的原因的,form-data和x-www-form-urlencoded都会改变请求参数,通过上面的对比都能看出来了。

    在这里插入图片描述

    请求体中的数据就是原始的传递数据,并不会改变
    在这里插入图片描述

    04.json数组映射对象数组

    /**
     * 传递对象数组
     * */
    @PostMapping("/post04")
    public Comment[] post04(@RequestBody Comment[] comments) {
    	return comments;
    }
    

    请求参数为一个json数组,这个东西以前可是难到我了,我去网上找了一个直接映射成List的写法,但是后来遇到这个问题我一想,既然单个json是一个对象,那么json数组,不就是一个对象数组吗?试了一下,果然是这样的!
    在这里插入图片描述
    在这里插入图片描述

    05.json数组映射List

    @PostMapping("/post05")
    public List<Comment> post05(@RequestBody List<Comment> commentList) {
    	return commentList;
    }
    

    请求参数直接映射成List
    在这里插入图片描述
    在这里插入图片描述

    06.传递二进制数据(文件)

    /**
     * 传递二进制数据
     * */
    @PostMapping("/upload")
    public String uploadFile(@RequestParam("file") MultipartFile file) {	
    	if (!file.isEmpty()) {
    		String fileName = file.getOriginalFilename();
    		try {
    			file.transferTo(new File(baseDir, fileName)); // 对于 SpringBoot 中使用路径还是懵逼!
    			return "success";
    		} catch (IllegalStateException e) {
    			e.printStackTrace();
    		} catch (IOException e) {
    			e.printStackTrace();
    		}
    	} 
    	return "Fail";
    }
    

    以前使用Servlet的时候,上传文件是很复杂的,后来Servlet3.0中进行了改进,现在框架又进行了进一步的封装,使用起来更加方便了。
    在这里插入图片描述
    在这里插入图片描述

    在这里插入图片描述

    请求报文
    在这里插入图片描述
    在这里插入图片描述

    8.表单数据(文本+文件)

    /**
     *  表单数据,含文本和二进制
     * */
    @PostMapping("/submitInfo01")
    public String submitInfo(@RequestParam("id") String id,
    		@RequestParam("name") String name,
    		@RequestParam("file") MultipartFile file) {
    	
    	System.out.println("id: " + id);
    	System.out.println("name: " + name);
    	System.out.println("fileName: " + file != null ? file.getOriginalFilename() : "null");
    	
    	if (!file.isEmpty()) {
    		String fileName = file.getOriginalFilename();
    		try {
    			file.transferTo(new File(baseDir, fileName));
    			return "success";
    		} catch (IllegalStateException e) {
    			e.printStackTrace();
    		} catch (IOException e) {
    			e.printStackTrace();
    		}
    	} 
    	return "Fail";
    }
    

    表单通常是可以携带不同的数据,主要是因为它的形式很适合这样做,所以可以同时接收文件和文本数据。表单数据使用一个boundary来隔开不同的数据。
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    09.表单数据,进一步封装成对象

    上面那样如果表单项比较多的话,映射还是比较麻烦的,可以选择创建一个对象封装所有的属性,这样处理起来就会更加方便,并且也是面向对象思想的应用。

    /**
     *    表单数据,含文本和二进制 进一步封装!
     * */
    @PostMapping("/submitInfo02")
    public String submitInfo02(User user) {
    	
    	MultipartFile file = user.getFile();
    	System.out.println("id: " + user.getId());
    	System.out.println("name: " + user.getName());
    	System.out.println("fileName: " + user != null ? file.getOriginalFilename() : "null");
    	
    	if (!file.isEmpty()) {
    		String fileName = file.getOriginalFilename();
    		try {
    			file.transferTo(new File(baseDir, fileName));
    			return "success";
    		} catch (IllegalStateException e) {
    			e.printStackTrace();
    		} catch (IOException e) {
    			e.printStackTrace();
    		}
    	} 
    	return "Fail";
    }
    

    在这里插入图片描述

    在这里插入图片描述

    10.ajax2.0传递二进制数据

    /**
     * POST以二进制形式传递文件,通常的web表单是做不到的,但是ajax2.0以后是支持的,我们来尝试一下。
     * 注意它和 Multipart的区别,Multipart实际上不只包含文件本身的数据,还有文件的其它的信息,例如刚才获取的文件名。
     * 但是如果以二进制的形式传递,它就是完全的文件数据流,不包含任何其它信息,只有文件本身的二进制数据流。
     * 
     * 使用这种形式,只能传输单个文件,无法传输多个文件,因为它只是文件本身的二进制数据,如果是多个的话,
     * 那么谁也别想从一个连续的二进制流中把图片切分出来了。
     * */
    @PostMapping("/binaryFile")
    public String binaryFile(@RequestBody byte[] fileData) {
    	try {
    		Files.write(Paths.get(baseDir, UUID.randomUUID().toString() + ".jpg"), fileData);
    		return "success";
    	} catch (IOException e) {
    		e.printStackTrace();
    		return e.getMessage();
    	}
    }
    

    在这里插入图片描述

    在这里插入图片描述
    在这里插入图片描述

    baseDir路径下的文件

    在这里插入图片描述

    增补拾遗

    GET请求方式,也是可以在映射请求体中的数据的,但是对报文的Content-Type有要求,并且不推荐这样使用!

    /**
     *  使用对象对参数进行封装,这样在多个参数时,优势很明显。
     *  但是这里无法使用 @RequestParam注解,否则会出错。
     * */
    @GetMapping("/get04")
    public Comment get04(Comment comment) {
    	if (Objects.isNull(comment)) {
    		return null;  // 需要对 null 值进行处理
    	}
    	System.out.println(comment);
    	return comment;
    }
    

    Content-Type: x-www-form-urlencoded

    注:无法接收参数
    在这里插入图片描述

    在这里插入图片描述

    Content-Type: form-data
    注:可以接收数据。
    在这里插入图片描述
    在这里插入图片描述

    /**
      * 使用对象封装参数要求必须具有一个对象,所以可以使用 Map 来封装,这样可以减少对象的数
      * 量。 
      * * */
    @GetMapping("/get05")
    public Map<String, String> get05(@RequestParam Map<String, String> map) {
    	map.forEach((k, v) -> {
    		System.out.println(k + " --> " + v);
    	});
    	System.out.println(map.size());
    	return map;
    }
    

    在这里插入图片描述
    在这里插入图片描述

    在这里插入图片描述

    GET请求,但是数据在请求体中

    这种方式违背了通常的web数据传输,因为我们通常是规定GET方式没有请求体,POST方式数据在请求体中的。但是GET方式是可以有请求体的,POST方式也可以把参数方式放到请求行中,甚至于GET和POST的请求行和请求体中都可以携带数据。但是这样的话,可就苦了前端了,因为表单的发送请求的形式基本是固定的,出了ajax可以多一些花样。所以,如果你是一个GET请求,但是使用@RequestBody来接收参数,这个可就够前端难受的了。年轻人要讲究武德,不要乱用,但是不是不能用,如果不是Web项目,那就可以随便用了。

    @GetMapping("/not_use_like_this")
    public Comment not_use_like_this(@RequestBody Comment comment) {
    	System.out.println(comment);
    	return comment;
    }
    

    在这里插入图片描述

    在这里插入图片描述

    全部代码

    目录结构

    package request_learn;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    
    @SpringBootApplication
    public class LearnApplication {
    	
    	public static void main(String[] args) {
    		SpringApplication.run(LearnApplication.class, args);
    	}
    	
    }
    
    
    package request_learn.entity;
    
    import java.io.Serializable;
    
    public class Comment implements Serializable {
    
    	private static final long serialVersionUID = 1L;
    	
    	private String id;
    	private String name;
    	private String comment;
    	
    	// 省略getter、setter和toString方法
    }
    
    
    package request_learn.entity;
    
    import org.springframework.web.multipart.MultipartFile;
    
    public class User {
    	
    	private String id;
    	private String name;
    	private MultipartFile file;
    	
    	// 省略getter、setter和toString方法
    }
    
    
    package request_learn.controller;
    
    import java.io.BufferedInputStream;
    import java.io.BufferedOutputStream;
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.OutputStream;
    import java.nio.file.Files;
    import java.nio.file.Paths;
    import java.util.List;
    import java.util.Map;
    import java.util.Objects;
    import java.util.UUID;
    
    import javax.servlet.http.HttpServletResponse;
    
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.PathVariable;
    import org.springframework.web.bind.annotation.PostMapping;
    import org.springframework.web.bind.annotation.RequestBody;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestParam;
    import org.springframework.web.bind.annotation.RestController;
    import org.springframework.web.multipart.MultipartFile;
    
    import request_learn.entity.Comment;
    import request_learn.entity.User;
    
    @RestController
    @RequestMapping("/test")
    public class LearnController {
    
    	private static final String baseDir = "D:/test/img/";
    	
    	/**
    	 * GET 方式传递参数  单个参数
    	 * */
    	@GetMapping("/get01")
    	public String get01(String comment) {
    		return comment == null ? "no parameter" : comment;
    	}
    	
    	
    	@GetMapping("/get02")
    	public String get02(@RequestParam("comment") String comment) {
    		return comment;
    	}
    	
    	/**
    	 * GET 方式传递参数  多个个参数
    	 * */
    	@GetMapping("/get03")
    	public String get03(@RequestParam("id") String id,
    			@RequestParam("name") String name,
    			@RequestParam("comment") String comment) {
    		System.out.println(id + " " + name + " " + comment);		
    		return id + " " + name + " " + comment;
    	}
    	
    	/**
    	 *  使用对象对参数进行封装,这样在多个参数时,优势很明显。
    	 *  但是这里无法使用 @RequestParam注解,否则会出错。
    	 * */
    	@GetMapping("/get04")
    	public Comment get04(Comment comment) {
    		if (Objects.isNull(comment)) {
    			return null;  // 需要对 null 值进行处理
    		}
    		System.out.println(comment);
    		return comment;
    	}
    	
    	/**
    	 * 使用对象封装参数要求必须具有一个对象,所以可以使用 Map 来封装,这样可以减少对象的数量。
    	 * */
    	@GetMapping("/get05")
    	public Map<String, String> get05(@RequestParam Map<String, String> map) {
    		map.forEach((k, v) -> {
    			System.out.println(k + " --> " + v);
    		});
    		System.out.println(map.size());
    		return map;
    	}
    	
    	/**
    	 * 参数和路径结合,适用于单个参数的情况
    	 * */
    	@GetMapping("/get06/{id}")
    	public Comment getById(@PathVariable("id") String id) {
    		Comment comment = new Comment();
    		comment.setId(id);
    		comment.setName("Alfred");
    		comment.setComment("I love you yesterday and today!");
    		return comment;
    	}
    	
    	/**
    	 * 返回值为二进制
    	 * */
    	@GetMapping("/get07/{name}")
    	public void getFile(@PathVariable("name") String name, HttpServletResponse response) {
    		try (OutputStream out = new BufferedOutputStream(response.getOutputStream())) {
    			try (InputStream in = new BufferedInputStream(new FileInputStream(new File(baseDir, name)))) {
    				int len = 0;
    				byte[] data = new byte[4*1024];
    				while ((len = in.read(data)) != -1) {
    					out.write(data, 0, len);
    				}
    			}
    		} catch (IOException e) {
    			e.printStackTrace();
    		}
    	}
    	
    	
    	/**
    	 * POST方式传递参数
    	 * @return 
    	 * */
    	@PostMapping("/post01")
    	public String post01(@RequestParam("id") String id,
    			@RequestParam("name") String name,
    			@RequestParam("comment") String comment) {
    		System.out.println(id + " " + name + " " + comment);		
    		return id + " " + name + " " + comment;
    	}
    	
    	@PostMapping("/post02")
    	public Map<String, String> post02(@RequestParam Map<String, String> map) {
    		map.forEach((k, v) -> {
    			System.out.println(k + " --> " + v);
    		});
    		return map;
    	}
    	
    	
    	@PostMapping("/post03")
    	public Comment post03(@RequestBody Comment comment) {
    		System.out.println(comment);
    		return comment;
    	}
    	
    	
    	/**
    	 *    传递二进制数据
    	 * */
    	@PostMapping("/upload")
    	public String uploadFile(@RequestParam("file") MultipartFile file) {	
    		if (!file.isEmpty()) {
    			String fileName = file.getOriginalFilename();
    			try {
    				file.transferTo(new File(baseDir, fileName)); // 对于 SpringBoot 中使用路径还是懵逼!
    				return "success";
    			} catch (IllegalStateException e) {
    				e.printStackTrace();
    			} catch (IOException e) {
    				e.printStackTrace();
    			}
    		} 
    		return "Fail";
    	}
    	
    	
    	/**
    	 * 传递对象数据
    	 * */
    	@PostMapping("/post04")
    	public Comment[] post04(@RequestBody Comment[] comments) {
    		return comments;
    	}
    	
    	@PostMapping("/post05")
    	public List<Comment> post05(@RequestBody List<Comment> commentList) {
    		return commentList;
    	}
    	
    	
    	/**
    	 *    表单数据,含文本和二进制
    	 * */
    	@PostMapping("/submitInfo01")
    	public String submitInfo(@RequestParam("id") String id,
    			@RequestParam("name") String name,
    			@RequestParam("file") MultipartFile file) {
    		
    		System.out.println("id: " + id);
    		System.out.println("name: " + name);
    		System.out.println("fileName: " + file != null ? file.getOriginalFilename() : "null");
    		
    		if (!file.isEmpty()) {
    			String fileName = file.getOriginalFilename();
    			try {
    				file.transferTo(new File(baseDir, fileName));
    				return "success";
    			} catch (IllegalStateException e) {
    				e.printStackTrace();
    			} catch (IOException e) {
    				e.printStackTrace();
    			}
    		} 
    		return "Fail";
    	}
    	
    	/**
    	 *    表单数据,含文本和二进制 进一步封装!
    	 * */
    	@PostMapping("/submitInfo02")
    	public String submitInfo02(User user) {
    		
    		MultipartFile file = user.getFile();
    		System.out.println("id: " + user.getId());
    		System.out.println("name: " + user.getName());
    		System.out.println("fileName: " + user != null ? file.getOriginalFilename() : "null");
    		
    		if (!file.isEmpty()) {
    			String fileName = file.getOriginalFilename();
    			try {
    				file.transferTo(new File(baseDir, fileName));
    				return "success";
    			} catch (IllegalStateException e) {
    				e.printStackTrace();
    			} catch (IOException e) {
    				e.printStackTrace();
    			}
    		} 
    		return "Fail";
    	}
    	
    	/**
    	 * POST以二进制形式传递文件,通常的web表单是做不到的,但是ajax2.0以后是支持的,我们来尝试一下。
    	 * 注意它和 Multipart的区别,Multipart实际上不只包含文件本身的数据,还有文件的其它的信息,例如刚才获取的文件名。
    	 * 但是如果以二进制的形式传递,它就是完全的文件数据流,不包含任何其它信息,只有文件本身的二进制数据流。
    	 * 
    	 * 使用这种形式,只能传输单个文件,无法传输多个文件,因为它只是文件本身的二进制数据,如果是多个的话,
    	 * 那么谁也别想从一个连续的二进制流中把图片切分出来了。
    	 * */
    	@PostMapping("/binaryFile")
    	public String binaryFile(@RequestBody byte[] fileData) {
    		try {
    			Files.write(Paths.get(baseDir, UUID.randomUUID().toString() + ".jpg"), fileData);
    			return "success";
    		} catch (IOException e) {
    			e.printStackTrace();
    			return e.getMessage();
    		}
    	}
    	
    	
    	@GetMapping("/not_use_like_this")
    	public Comment not_use_like_this(@RequestBody Comment comment) {
    		System.out.println(comment);
    		return comment;
    	}
    }
    
    

    总结

    通过列举多种参数传递的方式,并且实际使用Postman和Fiddler测试,我觉得自己对于大部分的参数传递方式都已经很熟练了,这确实是一种很好的学习方式。我本身是属于视觉学习型的人,所以对我来说学习一样东西,亲眼所见的效果是最好的。大家也要多探索属于自己的学习方式。

    这里只是一些具体的案例,但是关于@RequestPram和@RequestBody的实际作用,这里我还不是太了解,还需要以后多学习,这里贴一段它本身的API说明。

    In Spring MVC, “request parameters” map to query parameters, form data,
    and parts in multipart requests. This is because the Servlet API combines
    query parameters and form data into a single map called “parameters”, and
    that includes automatic parsing of the request body.

    1.query paramters
    2.from data
    3.parts in multipart

    这样看来 @RequestParam 同时适用于GET和POST方法,但是更加准确的解释应该是它
    可以处理在请求行和请求体中的参数(上面三种情况)。

    注意:虽然它适用范围很广,但是也不是说可以随便使用的,也是有限制条件的。

    PS:
    1. 上面列举的情况还是不够,如果有漏网之鱼,可以在评论区中提出来,我再增补上去。
    2. 大家可以数一下,我总共列举了多少种参数传递的情况。

    展开全文
  • 三种参数传递方式

    千次阅读 2018-10-09 20:39:49
    在函数定义和调用时,有三种常见的参数传递方式: 1.传值 2.传指针 3.传引用 下面给出一个例子说明参数传递的三种方式 #include&lt;iostream&gt; using namespace std; void swap1(int a,int b) {...

    在函数定义和调用时,有三种常见的参数传递方式:

    1.传值

    2.传指针

    3.传引用

     

    下面给出一个例子说明参数传递的三种方式

    #include<iostream>
    
    using namespace std;
    
    void swap1(int a,int b)
    {
        int t;
        t=a;
        a=b;
        b=t;
    }
    
    void swap2(int* a,int* b)
    {
        int t;
        t=*a;
        *a=*b;
        *b=t;
    }
    
    void swap3(int &a,int &b)
    {
        int t;
        t=a;
        a=b;
        b=t;
    }
    
    
    int main()
    {
        int x=10,y=20;
        swap1(x,y);
        cout<<x<<' '<<y<<endl;
        swap2(&x,&y);
        cout<<x<<' '<<y<<endl;
        swap3(x,y);
        cout<<x<<' '<<y<<endl;
        return 0;
    }

     

    特别说明:数组参数的传递方式属于特殊情况。数组作为形参按传值方式声明,但实际传递的是数组的首地址(即数组名),使得形参数组和实参数组共用同一组内存单元。

    因此性参数组所作的任何改变相当于在实参数组中进行相应的处理

     

    展开全文
  • java方法参数传递方式--按值传递、引用传递

    万次阅读 多人点赞 2017-12-25 21:33:28
    java的方法参数传递方式有两种,按值传递和引用传递 1.按值传递
  • spring MVC 的参数传递方式

    千次阅读 2017-11-15 15:23:27
     在使用spring的项目中,前台传递参数到后台是经常遇到的事, 我们必须熟练掌握一些常用的参数传递方式和注解的使用,废话少说,直接上正文。 1. @requestMapping: 类级别和方法级别的注解, 指明前后台解析的路径...
  • java的方法参数传递方式有两种,按值传递和引用传递 1.按值传递 参数类型是int,long等基本数据类型(八大基本数据类型),参数传递的过程采用值拷贝的方式 代码片段1: public class Test { public static void ...
  • Java函数参数传递方式详解

    千次阅读 2018-06-21 09:29:03
    转:http://zzproc.iteye.com/blog/1328591 在阅读本文之前,根据自己的经验和理解,大家可以先思考并选择一下Java函数的参数传递方式: A. 是按值传递
  • PHP之同名参数传递方式

    千次阅读 2015-02-15 18:09:42
    PHP之同名参数传递方式
  • JSF参数传递方式

    千次阅读 2013-04-27 16:46:07
    JSF参数传递方式之一:f:param标签 页面到Bean的参数传递 页面中设置参数: Java代码 收藏代码             注意:这
  • C语言三种参数传递方式

    千次阅读 2015-11-12 15:55:23
    C语言中存在三种参数传递方式,分别是值传递,地址传递,引用传递;三种方式之间形式参数的区别到底是什么?三种方式在内存中的操作到底是什么样的? 本文通过几个例子来分析、总结。
  • java参数传递方式问题

    千次阅读 2014-04-24 08:20:02
    java的参数传递方式究竟是值传递还是引用传递一直是个备受争论的问题,在这里,我给出了自己的一些理解,纯属个人意见,仅供参考。
  • 原 C语言的3种参数传递方式 2017年09月14日 18:30:26 采香行处 阅读数:14619 </div> <div class="operating"> ...
  • Java两种参数传递方式的区别

    千次阅读 2018-03-06 11:53:33
    Java两种参数传递方式的区别 Java中没有指针,所以也没有引用传递了,仅仅有值传递不过可以通过对象的方式来实现引用传递 类似java没有多继承 但可以用多次implements 接口实现多继承的功能  值传递:方法...
  • python3 不允许我们选择参数传递方式,但是他已经全部采用了引用传递。 相关测试代码与解释贴在文章里了。
  • 函数参数传递方式详解

    千次阅读 2014-07-21 09:23:14
    1. 函数参数传递方式之一:值传递   (1)值传递的一个错误认识 先看如下的一个问题: void Exchg1(int x, int y) /* 定义中的x,y变量被称为Exchg1函数的形式参数 */ {  int tmp;  tmp = x;  x= y;  y...
  • 方法的参数传递方式

    2013-08-26 10:47:01
    2.java的参数传递方式只有一种:值传递。 值传递:将实际参数值的副本传入方法内,但实际的参数不受影响。 3.例如: ①基本数据类型 public class Test{ public static void swap(int a,int b){ int temp=a; ...
  • Java中的参数传递方式

    千次阅读 2014-03-12 10:34:14
    无论是什么语言,要讨论参数传递方式,就得从内存模型说起,主要是我个人觉得从内存模型来说参数传递更为直观一些。闲言少叙,下面我们就通过内存模型的方式来讨论一下Java中的参数传递。 这里的内存模型涉及到两...
  • C++中参数传递方式讨论

    千次阅读 2013-08-05 23:01:53
    众所周知,在C++中调用函数时有三种参数传递方式:  (1)传值调用;  (2)传址调用(传指针);  (3)引用传递;  实际上,还有一种参数传递方式,就是全局变量传递方式。这里的“全局”变量并不见得就是...
  • 3种函数参数传递方式

    千次阅读 2014-11-23 14:50:54
    3种函数参数传递方式 1. 将变量名作为形参和实参 在这种情况下传给形参的是变量的值。传递是单向的,即如果在执行函数期间形参的值发生变化,并不传回给实参,这就是值传递方式。因为在调用函数期间,形参和实参...
  • js 参数传递方式:按值传递

    万次阅读 2017-12-21 10:29:29
    在向参数传递基本类型的值时,被传递的值会被复制给命名参数,引用类型时,传递的是它指针内存储的值 借用网上的一个例子 function setName(obj){ obj.name="nick"; console.log('第一次'+obj); ...
  • python list 参数传递方式

    万次阅读 2017-11-07 19:18:42
    python list 参数传递
  • python参数传递方式

    千次阅读 2017-02-06 09:06:03
    python参数传递是以传引用的方式!如果函数接收到的参数是一个可变对象(类类型,列表,字典),就会改变对象的原始值。 如果函数接收到的参数是一个不可变对象,即基本数据类型(数值型,字符串,布尔),就不会改变...
  • 言归正传,都2020年了,居然还有人认为java的参数传递方式是引用传递,今天我就来讲一讲java的参数传递,好好看,写的不对的地方,请大声说出来,反正我也不会改,憋坏了就不好了。 基本数据类型传递 我们先来看一...
  • Java学习(八)方法参数传递方式

    千次阅读 2014-11-13 14:32:47
    Java学习(八)方法参数传递方式
  • Java中参数传递方式(超详细)

    千次阅读 2014-11-21 16:50:32
    无论是什么语言,要讨论参数传递方式,就得从内存模型说起,主要是我个人觉得从内存模型来说参数传递更为直观一些。闲言少叙,下面我们就通过内存模型的方式来讨论一下Java中的参数传递。 这里的内存模型涉及到两种...
  • Delphi中的参数传递方式

    千次阅读 2004-10-30 09:17:00
    参数传递方式: Delphi中有自己的参数传递方式,而Windows API也有自己的参数传递方式,那么他们之间有什么不同呢,要如何做到兼容呢,尤其是在编写动态库时? (1)cdecl: 通常是C/C++所使用的参数传递方式,它的传递方式...
  • 几种参数传递方式

    2010-05-16 18:32:00
    著名的《CTM》中写有6种参数传递方式,比较有趣。1、Call by reference --传对象标识符2、Call by varible --是1的特例,传变量标识符3、Call by value-result --是2的变种,像PL/SQ和PascalL中的inout参数4、Call ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 28,725
精华内容 11,490
关键字:

参数传递方式