以下主要记录了学习web后端前对web前端的初步认识,主要涉及到:html、css、javascript的认识以及html、css、js的基础知识、json的认识,其中js的东西较多,在下一篇中继续详细介绍:
html概述及基础
HTML 主要用于网页主体结构的搭建。HTML5 是 HyperText Markup Language 5 的缩写,HTML5 技术结合了 HTML4.01 的相关标准并革新,符合现代网络发展要求,在 2008 年正式发布。HTML5 由不同的技术构成,其在互联网中得到了非常广泛的应用,提供更多增强网络应用的标准机。与传统的技术相比,HTML5 的语法特征更加明显,并且结合了 SVG 的内容。这些内容在网页中使用可以更加便捷地处理多媒体内容,而且 HTML5中还结合了其他元素,对原有的功能进行调整和修改,进行标准化工作。HTML5 在 2012 年已形成了稳定的版本。2014年10月28日,W3C发布了HTML5的最终版。
html的基础结构以及第一个程序
HTML文件中第一行的内容,用来告诉浏览器当前HTML文档的基本信息,其中最重要的就是当前HTML文档遵循的语法标准。这里我们只需要知道HTML有4和5这两个大的版本
HTML4版本的文档类型声明是:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
HTML5版本的文档类型声明是:
<!DOCTYPE html>
现在主流的技术选型都是使用HTML5,之前的版本基本不用了。
2根标签
html标签是整个文档的根标签,所有其他标签都必须放在html标签里面。
3头部元素
head标签用于定义文档的头部,其他头部元素都放在head标签里。头部元素包括title标签、script标签、style标签、link标签、meta标签等等。
4主体元素
body标签定义网页的主体内容,在浏览器窗口内显示的内容都定义到body标签内。
5注释
HTML注释的写法是
<!-- 注释内容 -->
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>我的第一个网页</title> </head> <body> hello html!!! </body> </html>
怎么从编写到运行?
1. 准备一个纯文本文件,拓展名为html
2. 使用记事本(或者ide)打开网页,在网页内开发代码
3. 使用浏览器打开文件,查看显示的内容
HTML概念词汇解释
标签
代码中的一个 <> 叫做一个标签,有些标签成对出现,称之为双标签,有些标签单独出现,称之为单标签
属性
一般在开始标签中,用于定义标签的一些特征
文本
双标签中间的文字,包含空格换行等结构
元素
经过浏览器解析后,每一个完整的标签(标签+属性+文本)可以称之为一个元素
HTML的语法规则
1 根标签有且只能有一个
2 无论是双标签还是单标签都需要正确关闭
3 标签可以嵌套但不能交叉嵌套
4 注释语法为<!-- --> ,注意不能嵌套
5 属性必须有值,值必须加引号,H5中属性名和值相同时可以省略属性值
6 HTML中不严格区分字符串使用单双引号
7 HTML标签不严格区分大小写,但是不能大小写混用
8 HTML中不允许自定义标签名,强行自定义则无效
html中有很多标签,需要时可以查阅在线文档:http://www.w3school.com.cn
css概述及基础
CSS 主要用于页面元素美化。css是一种层叠样式表 能够对网页中元素位置的排版进行像素级精确控制,支持几乎所有的字体字号样式,拥有对网页对象和模型样式编辑的能力。在html文件中引入css样式实现。
CSS引入方式
行内式,通过元素开始标签的style属性引入, 样式语法为 样式名:样式值; 样式名:样式值;
代码
<input type="button" value="按钮" style=" display: block; width: 60px; height: 40px; background-color: rgb(140, 235, 100); color: white; border: 3px solid green; font-size: 22px; font-family: '隶书'; line-height: 30px; border-radius: 5px; "/>
缺点
html代码和css样式代码交织在一起,增加阅读难度和维护成本
css样式代码仅对当前元素有效,代码重复量高,复用度低
内嵌式
代码
<head> <meta charset="UTF-8"> <style> /* 通过选择器确定样式的作用范围 */ input { display: block; width: 80px; height: 40px; background-color: rgb(140, 235, 100); color: white; border: 3px solid green; font-size: 22px; font-family: '隶书'; line-height: 30px; border-radius: 5px; } </style> </head> <body> <input type="button" value="按钮1"/> <input type="button" value="按钮2"/> <input type="button" value="按钮3"/> <input type="button" value="按钮4"/> </body>
说明
内嵌式样式需要在head标签中,通过一对style标签定义CSS样式
CSS样式的作用范围控制要依赖选择器
CSS的样式代码中注释的方式为 /* */
内嵌式虽然对样式代码做了抽取,但是CSS代码仍然在html文件中
内嵌样式仅仅能作用于当前文件,代码复用度还是不够,不利于网站风格统一
连接式/外部样式表
可以在项目单独创建css样式文件,专门用于存放CSS样式代码
在head标签中,通过link标签引入外部CSS样式即可
<head> <meta charset="UTF-8"> <link href="css/buttons.css" rel="stylesheet" type="text/css"/> </head> <body> <input type="button" value="按钮1"/> <input type="button" value="按钮2"/> <input type="button" value="按钮3"/> <input type="button" value="按钮4"/> </body>
说明
CSS样式代码从html文件中剥离,利于代码的维护
CSS样式文件可以被多个不同的html引入,利于网站风格统一
注意:第三种引入中,决定对某个元素装饰的是css选择器,不是link
CSS选择器
元素选择器
代码
<head> <meta charset="UTF-8"> <style> input { display: block; width: 80px; height: 40px; background-color: rgb(140, 235, 100); color: white; border: 3px solid green; font-size: 22px; font-family: '隶书'; line-height: 30px; border-radius: 5px; } </style> </head> <body> <input type="button" value="按钮1"/> <input type="button" value="按钮2"/> <input type="button" value="按钮3"/> <input type="button" value="按钮4"/> <button>按钮5</button> </body>
说明
根据标签名确定样式的作用范围
语法为 元素名 {}
样式只能作用到同名标签上,其他标签不可用
相同的标签未必需要相同的样式,会造成样式的作用范围太大
id选择器
代码
<head> <meta charset="UTF-8"> <style> #btn1 { display: block; width: 80px; height: 40px; background-color: rgb(140, 235, 100); color: white; border: 3px solid green; font-size: 22px; font-family: '隶书'; line-height: 30px; border-radius: 5px; } </style> </head> <body> <input id="btn1" type="button" value="按钮1"/> <input id="btn2" type="button" value="按钮2"/> <input id="btn3" type="button" value="按钮3"/> <input id="btn4" type="button" value="按钮4"/> <button id="btn5">按钮5</button> </body>
说明
根据元素id属性的值确定样式的作用范围
语法为 #id值 {}
id属性的值在页面上具有唯一性,所有id选择器也只能影响一个元素的样式
因为id属性值不够灵活,所以使用该选择器的情况较少
class选择器
代码
<head> <meta charset="UTF-8"> <style> .shapeClass { display: block; width: 80px; height: 40px; border-radius: 5px; } .colorClass{ background-color: rgb(140, 235, 100); color: white; border: 3px solid green; } .fontClass { font-size: 22px; font-family: '隶书'; line-height: 30px; } </style> </head> <body> <input class ="shapeClass colorClass fontClass"type="button" value="按钮1"/> <input class ="shapeClass colorClass" type="button" value="按钮2"/> <input class ="colorClass fontClass" type="button" value="按钮3"/> <input class ="fontClass" type="button" value="按钮4"/> <button class="shapeClass colorClass fontClass" >按钮5</button> </body>
说明
根据元素class属性的值确定样式的作用范围
语法为 .class值 {}
class属性值可以有一个,也可以有多个,多个不同的标签也可以是使用相同的class值
多个选择器的样式可以在同一个元素上进行叠加
因为class选择器非常灵活,所以在CSS中,使用该选择器的情况较多
CSS浮动
CSS 的 Float(浮动)使元素脱离文档流,按照指定的方向(左或右发生移动),直到它的外边缘碰到包含框或另一个浮动框的边框为止。
浮动设计的初衷为了解决文字环绕图片问题,浮动后一定不会将文字挡住,这是设计初衷。
文档流是是文档中可显示对象在排列时所占用的位置/空间,而脱离文档流就是在页面中不占位置了。
浮动的样式名:float
通过代码感受浮动的效果
<head> <meta charset="UTF-8"> <style> .outerDiv { width: 500px; height: 300px; border: 1px solid green; background-color: rgb(230, 224, 224); } .innerDiv{ width: 100px; height: 100px; border: 1px solid blue; float: left; } .d1{ background-color: greenyellow; /* float: right; */ } .d2{ background-color: rgb(79, 230, 124); } .d3{ background-color: rgb(26, 165, 208); } </style> </head> <body> <div class="outerDiv"> <div class="innerDiv d1">框1</div> <div class="innerDiv d2">框2</div> <div class="innerDiv d3">框3</div> </div> </body>
效果如下:就是让内层div块都向左浮动
CSS定位
position 属性指定了元素的定位类型。
这个属性定义建立元素布局所用的定位机制。任何元素都可以定位,不过绝对或固定元素会生成一个块级框,而不论该元素本身是什么类型。相对定位元素会相对于它在正常流中的默认位置偏移。
元素可以使用的顶部,底部,左侧和右侧属性定位。然而,这些属性无法工作,除非是先设定position属性。他们也有不同的工作方式,这取决于定位方法。
至于具体的效果,可以自行去看
CSS盒子模型
所有HTML元素可以看作盒子,在CSS中,"box model"这一术语是用来设计和布局时使用。
CSS盒模型本质上是一个盒子,封装周围的HTML元素,它包括:边距(margin),边框(border),填充(padding),和实际内容(content)
说明:
Margin(外边距) - 清除边框外的区域,外边距是透明的。
Border(边框) - 围绕在内边距和内容外的边框。
Padding(内边距) - 清除内容周围的区域,内边距是透明的。
Content(内容) - 盒子的内容,显示文本和图像。
代码
<head> <meta charset="UTF-8"> <style> .outerDiv { width: 800px; height: 300px; border: 1px solid green; background-color: rgb(230, 224, 224); margin: 0px auto; } .innerDiv{ width: 100px; height: 100px; border: 1px solid blue; float: left; /* margin-top: 10px; margin-right: 20px; margin-bottom: 30px; margin-left: 40px; */ margin: 10px 20px 30px 40px; } .d1{ background-color: greenyellow; /* padding-top: 10px; padding-right: 20px; padding-bottom: 30px; padding-left: 40px; */ padding: 10px 20px 30px 40px; } .d2{ background-color: rgb(79, 230, 124); } .d3{ background-color: rgb(26, 165, 208); } </style> </head> <body> <div class="outerDiv"> <div class="innerDiv d1">框1</div> <div class="innerDiv d2">框2</div> <div class="innerDiv d3">框3</div> </div> </body>
效果
在浏览器上,通过F12工具查看盒子模型状态
json的认识和使用
js概述及部分基础
JavaScript 主要用于页面元素的动态处理。
Javascript是一种由Netscape(网景)的LiveScript发展而来的原型化继承的面向对象的动态类型的区分大小写的客户端脚本语言
,主要目的是为了解决服务器端语言,遗留的速度问题,为客户提供更流畅的浏览效果。当时服务端需要对数据进行验证,由于网络速度相当缓慢,只有28.8kbps,验证步骤浪费的时间太多。于是Netscape的浏览器Navigator加入了Javascript,提供了数据验证的基本功能。ECMA-262 是正式的 JavaScript 标准。这个标准基于 JavaScript (Netscape) 和 JScript (Microsoft)。ECMA-262 的开发始于 1996 年,在 1997 年 7 月,ECMA 会员大会采纳了它的首个版本。这个标准由 ECMA 组织发展和维护。JavaScript 的正式名称是 "ECMAScript"。JavaScript的组成包含ECMAScript、DOM、BOM。JS是一种运行于浏览器端上的小脚本语句,可以实现网页如文本内容动,数据动态变化和动画特效等,JS有 如下特点:
脚本语言
JavaScript是一种解释型的脚本语言。不同于C、C++、Java等语言先编译后执行, JavaScript不会产生编译出来的字节码文件,而是在程序的运行过程中对源文件逐行进行解释。
基于对象
JavaScript是一种基于对象的脚本语言,它不仅可以创建对象,也能使用现有的对象。但是面向对象的三大特性:『封装』、『继承』、『多态』中,JavaScript能够实现封装,可以模拟继承,不支持多态,所以它不是一门面向对象的编程语言。
弱类型
JavaScript中也有明确的数据类型,但是声明一个变量后它可以接收任何类型的数据,并且会在程序执行过程中根据上下文自动转换类型。
事件驱动
JavaScript是一种采用事件驱动的脚本语言,它不需要经过Web服务器就可以对用户的输入做出响应。
跨平台性
JavaScript脚本语言不依赖于操作系统,仅需要浏览器的支持。因此一个JavaScript脚本在编写后可以带到任意机器上使用,前提是机器上的浏览器支持JavaScript脚本语言。目前JavaScript已被大多数的浏览器所支持。
js的语法方面和java有相同之处,也有不同:下面通过代码和注释解释js的基础语法
js的引入方式
<!DOCTYPE html> <html> <head> <title>Demo</title> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width,initial-scale=1.0"> <style> .btn1{ width: 150px; height: 40px; font-size: 24px; font-family: 隶书; background-color: yellow; color: red; border: 3px solid red; border-radius: 5px; } </style> <!-- js引入方式 1. 内嵌式 在head中通过一对script标签定义脚本代码 2. 引入外部脚本文件 在head中通过一对script标签引入外部js文件 注意: 1. 一个html中可以有多对script标签 2. 一对script标签不能 引入外部js文件 的同时 定义内部脚本 3. script标签如果用于引入外部js文件,中间不能写其他东西,写了也无效 --> <!-- <script> /* 1.js如何声明函数? function 函数名(){} 2.函数如何和单击按钮的行为绑定到一起? 将按钮的行为属性值设置为函数名() 注意:()不能丢 3.如何弹窗提示? 浏览器的alert函数 */ function surprise(){ //弹窗提示 alert("hello 我是惊喜") } </script> --> <!-- src:资源路径 type:资源类型(这里是文本类型的脚本) --> <script src="js/button.js" type="text/javascript"></script> </head> <body> <button class="btn1" onclick="surprise()">单击点我</button> <button class="btn1" ondblclick="surprise()">双击点我</button> </body> </html>
其中引入的外部文件:这是js文件
function surprise(){ //弹窗提示 alert("hello 我是惊喜") }
js变量和数据类型
<!DOCTYPE html> <html> <head> <title>Demo</title> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width,initial-scale=1.0"> <script> /* 1. js中变量的声明是弱类型的 统统使用var 只有赋值时才确定类型 2. js常见的数据类型 数值类型 number 整数 小数 字符串类型 string 布尔类型 boolean 引用类型 Object function类型 function 命名未赋值 undefined 值:undefined 赋予null Object 值:null 判断数据类型的运算符 typeof 3. 变量可以重复声明 4. 变量可以使用不同数据类型多次赋值 5. js语句可以用 ; 结尾,也可以不用 ; 6. 标识符命名参照java 7. 如果使用了一个未声明的变量,会报出:uncaught Reference未捕获异常 8. 如果使用了一个声明了但没有赋值的变量,值为undefined 9. js中向浏览器控制台打印:console.log() 10. js中浏览器提示:alert() */ </script> </head> <body> </body> </html>
js的运算符
<!DOCTYPE html> <html> <head> <title>Demo</title> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width,initial-scale=1.0"> <script> /* 运算符: 1.算术 + - * / % 2.复合算术 += -= *= /= %= 不同: 除0:Infinity (正无穷) 模0:NaN not a number (不是一个数) 3.关系 > < >= <= == === 不同: ==:如果两端数据类型不同,会先尝试将两端转换为number再比较 注意:true就是1,不是非0(看以下的例子) ===:如果两端数据类型不同,直接返回false(严格等于) 4.逻辑 || && 5.条件 条件表达式?值1:值2 6.位 | & ^ << >> >>> */ console.log(1==0)/*false*/ console.log(1==1)/*true*/ console.log(1=="1")/*true*/ console.log(1==2)/*false*/ console.log(1==true)/*true*/ console.log(2==true)/*false*/ </script> </head> <body> </body> </html>
js分支结构
<!DOCTYPE html> <html> <head> <title>分支结构</title> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width,initial-scale=1.0"> <!-- 1.浏览器下弹窗提示输入:prompt 有返回值,默认为 字符串类型 2.if中非空字符串、非空对象、非0number都是true。相比于java只能用布尔类型 3.switch中任何变量 --> <script> var a = 5; var b = prompt("请输入:"); if(a == b){ console.log(true); }else{ console.log(false); } </script> </head> <body> </body> </html>
js循环结构
<!DOCTYPE html> <html> <head> <title>循环结构</title> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width,initial-scale=1.0"> <!-- 1.向浏览器窗口打印函数:document.write(); 2.js中打印空格时,如果直接“ ”,那么中间不论空多大都是一个空格字符,或者后面跟上多个“ ”,都是一个空格字符 3.js中写html语句需要用双引号或者单引号或者可以同时使用 4.js中使用document.write()函数拼接出html代码运行 5.js中的增强for语法: for(var index in 数组){ ... } 其中,index是索引,不是取到的数组元素;in代替java中 ":" ; --> <script> var i = 1; while(i<=9){ var j = 1; while(j<=i){ document.write(j+"*"+i+"="+(j*i)+" "); j++; } document.write("<hr>"); i++; } </script> </head> <body> </body> </html>
js函数
<!DOCTYPE html> <html> <head> <title>函数</title> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width,initial-scale=1.0"> <!-- 函数声明语法: 1.function 函数名(){} 2.var 函数名 = function(){} var 函数名 = function()函数名2{} (匿名函数表达式)使用函数时调用函数名,函数名2在函数外部不可见 和java相比注意: 1.没有权限修饰符 2.没有返回值类型(没有void),如果有返回值直接return即可 3.没有异常列表 4.参数列表中参数没有参数类型 5.调用方法时,形参和实参数量可以不一样,按顺序依次赋值;在方法内部可以通过arguments获得调用时的实参 其中,实参多,无所谓按顺序赋值;实参少,那么剩下的变量值为undefined 6.函数声明定义位置无所谓,JavaScript 支持函数声明提升(hoisting) 7.但是函数表达式形式的定义需要先声明后调用 8*. 函数嵌套:把函数当作变量使用,直接把一个函数作为变量放在另一个函数参数中 --> <script> var res = sum(1,2,3,4)//3 var res1 = sum(1,2)//3 var res2 = sum(1)//1 + undefined = NaN console.log(res,res1,res2) function sum(a,b){ return a+b; } </script> </head> <body> </body> </html>
js对象的创建
<!DOCTYPE html> <html> <head> <title>js对象的创建</title> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width,initial-scale=1.0"> <!-- 创建对象的两种主要方法: 1.var 对象名 = new Object() ,剩下的对象的属性和方法可以通过赋值的形式添加 2.var 对象名 = { "属性":"值" ,"方法":function(参数){方法体} } 其中双引号可以加可以不加,最好加上 --> <script> //1.第一种 var people = new Object(); //初始化,属性没有就创建并赋值 people.name = "张三"; people.eat = function(){ console.log("我要吃饭"); } //第二种 var person = { "name" : "李四", age : 10, eat(){ console.log("我要吃饭"); }, run:function(){ console.log("我要跑步"); } /* function可以省略 */ } //访问对象属性、调用对象方法 console.log(people.name) console.log(people.eat) console.log(person.name) console.log(person.eat) console.log(person.run) </script> </head> <body> </body> </html>
js中使用JSON
什么是json?
JSON(JavaScript Object Notation, JS对象简谱)是一种轻量级的数据交换格式。它基于ECMAScript(European Computer Manufacturers Association, 欧洲计算机协会的一个子集,采用完全独立于编程语言的文本格式来存储和表示数据。简洁和清晰的层次结构使得 JSON 成为理想的数据交换语言。 易于人阅读和编写,同时也易于机器解析和生成,并有效地提升网络传输效率 简单来说,JSON 就是一种字符串格式,这种格式无论是在前端还是在后端,都可以很容易的转换成对象,所以常用于前后端数据传递
1.JSON是什么?
是一种特定格式的字符串
2.JSON是用来解决什么问题的?
前后端语言不同,在进行数据交换时,数据的载体是一个又一个的对象,不同语言的对象不能之间使用,因此需要一种形式传输对象数据。
这种形式就是 JSON ,它使用字符串的形式将对象数据在网络中进行传输
3.JSON的格式:
var 对象名(JSON串名) = '{"属性":"值","属性":"值","对象属性":{"属性":"值"},"数组属性":["值1,值2"],"对象数组属性":[{"属性":"值"},{},{}] }'
其中:
属性可以是一般属性、数组、对象、对象数组...(但是属性其实就是一个名字)
值可以是一般属性、数组、对象、对象数组...(数组[],对象{},对象数组[{},{}])
4.JSON字符串前端的用法以及注意事项
js中对JSON串的解析(转换为对象):JSON.parse(JSON串)
js中把对象变成JSON串:JSON.stringify(对象)
注意:
JSON串只是一个字符串,不能访问到原本对象的相关属性
前端中定义一个JSON串 和 解析一个JSON串
/* 定义一个JSON串 */ var personStr ='{"name":"张小明","age":20,"girlFriend":{"name":"铁铃","age":23},"foods":["苹果","香蕉","橘子","葡萄"],"pets":[{"petName":"大黄","petType":"dog"},{"petName":"小花","petType":"cat"}]}' console.log(personStr) console.log(typeof personStr) /* 将一个JSON串转换为对象 */ var person =JSON.parse(personStr); console.log(person) console.log(typeof person) /* 获取对象属性值 */ console.log(person.name) console.log(person.age) console.log(person.girlFriend.name) console.log(person.foods[1]) console.log(person.pets[1].petName) console.log(person.pets[1].petType)
/* 定义一个对象 */ var person={ 'name':'张小明', 'age':20, 'girlFriend':{ 'name':'铁铃', 'age':23 }, 'foods':['苹果','香蕉','橘子','葡萄'], 'pets':[ { 'petName':'大黄', 'petType':'dog' }, { 'petName':'小花', 'petType':'cat' } ] } /* 获取对象属性值 */ console.log(person.name) console.log(person.age) console.log(person.girlFriend.name) console.log(person.foods[1]) console.log(person.pets[1].petName) console.log(person.pets[1].petType) /* 将对象转换成JSON字符串 */ var personStr =JSON.stringify(person) console.log(personStr) console.log(typeof personStr)
后端中定义一个JSON串和解析一个JSON串,需要一个外部的依赖工具:jackson
最后的两个代码是两个实体类,利用单元测试分别对json的写(定义)和json的读(解析)
package com.yym.test; import com.fasterxml.jackson.databind.ObjectMapper; import com.yym.json.Dog; import com.yym.json.Person; import org.junit.Test; public class TestJson { @Test public void testWriteJson() throws Exception { //实例化一个person对象 将person对象转换为JSON串 Dog dog = new Dog("小黑"); Person person = new Person("张三",10,dog); //将person转换为一个字符串 ObjectMapper mapper = new ObjectMapper(); String personJson = mapper.writeValueAsString(person); System.out.println(personJson); } @Test public void testReadJson() throws Exception { String personJson = "{\"name\":\"张三\",\"age\":10,\"dog\":{\"name\":\"小黑\"}}"; ObjectMapper mapper = new ObjectMapper(); Person person = mapper.readValue(personJson, Person.class); System.out.println(person); } /* 1.map转换为json格式后和对象的形式相同 2.list 和 数组 转换为json格式后形式相同 */ }
package com.yym.json; import java.util.Objects; public class Dog { private String name; public Dog(String name) { this.name = name; } public Dog() { } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Dog dog = (Dog) o; return Objects.equals(name, dog.name); } @Override public int hashCode() { return Objects.hashCode(name); } @Override public String toString() { return "Dog{" + "name='" + name + '\'' + '}'; } }
package com.yym.json; import java.util.Objects; public class Person { private String name; private int age; private Dog dog; public Person(String name, int age, Dog dog) { this.name = name; this.age = age; this.dog = dog; } public Person() { } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public Dog getDog() { return dog; } public void setDog(Dog dog) { this.dog = dog; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Person person = (Person) o; return age == person.age && Objects.equals(name, person.name) && Objects.equals(dog, person.dog); } @Override public int hashCode() { return Objects.hash(name, age, dog); } @Override public String toString() { return "Person{" + "name='" + name + '\'' + ", age=" + age + ", dog=" + dog + '}'; } }