1. 成员属性
概念: 类中可以存放属性变量,简称属性。
- 位置:
- 如果一个变量定义在方法体中,就叫做局部变量。
- 如果一个变量定义在方法体外,类体中,就叫这个类的成员属性。
- 分类: 属性根据修饰符而分为六种:
public String name
:公共属性:跨包任何类可见。protected String name
:保护属性:跨包父子类可见。String name
:默认属性:同包可见。private String name
:私有属性:本类可见。static String name
:静态属性:共享且唯一。final String name
:常量属性:不可二次赋值属性,建议全大写。
- 默认值: 属性变量跟局部变量不同,属性变量拥有默认值。
byte
,short
,int
,long
默认值是0。float
,double
默认值是0.0。char
默认值是空格,\u0000
。boolean
默认值是false。- 引用数据类型的默认值全都是null。
练习: 02002-1
- 局部变量和属性变量的区别?
2. 成员方法
概念: 成员方法和成员属性一样,都是类中的一个成员。
- 分类: 方法根据修饰符分为8种:
public void fun(){}
:公共方法:跨包任何类可见。protected void fun(){}
:保护方法:跨包父子类可见。void fun(){}
:默认方法:同包可见。private void fun(){}
:私有方法:本类可见。static void fun(){}
:静态方法:共享且唯一。public fun(){}
:构造方法:俗称构造器,创造类时必须调用的方法。abstract void fun();
抽象方法:一个没有方法体的方法。final void fun(){}
最终方法:不能被重写。
- 方法四要素:
- 方法名: 方法的名字,命名规范同变量名,首字母小写驼峰,尽量使用动词。
- 返回类型: 方法要返回给调用者一个什么类型的数据如果没返回任何数据则类型为void。
- 形参列表: 方法要接收哪些类型的数据,多个数据用逗号隔开如果不需要传入数据,则该方法叫做无参方法。
- 方法体: 方法的逻辑代码,注意最好一个方法只做一件事。
2.1 方法的设计思路
流程: 当我们想要设计一个方法的时候,建议遵循以下顺序:
- 用途: 我想设计一个能够将两个数字加起来得出结果的方法。
- 访问权限: 这个方法我想让项目里的所有类都能访问:
public
- 静态与否: 这个方法我想让它属于每一个实例,而不是属于类:
- 不写
static
- 不写
- 返回值: 我想让这个方法最终返回给我一个
int
类型的结果:public int
- 方法名: 方法名就叫
addNum
:public int addNum()
- 形参列表: 我想调用这个方法的时候,肯定要接收两个int类型的变量:
public int addNum(int numA, int numB)
- 方法体: 编写方法的逻辑代码,一个方法只做一件事:
public int addNum(int numA, int numB){...}
源码: addNum()
public int addNum(int numA, int numB){
return numA + numB;
}
复制代码
源码: 测试addNum()
@Test
public int addNum(){
int result = addNum(1, 5);
System.out.println(result);
}
复制代码
2.2 方法的调用
源码: MethodCallDemo.java
/**
* @author JoeZhou
*/
public class MethodCallDemo {
public void methodA() {
System.out.println("普通、公共、非静态、无参");
}
public static void methodB() {
System.out.println("普通、公共、静态、无参");
}
public void methodC(String str) {
System.out.println("普通、公共、非静态、有参");
}
public static void methodD(String str, int b) {
System.out.println("普通、公共、非静态、有参");
}
}
复制代码
源码:
@Test
public void methodCall(){
MethodCallDemo methodCallDemo = new MethodCallDemo();
methodCallDemo.methodA();
MethodCallDemo.methodB();
methodCallDemo.methodC("");
MethodCallDemo.methodD("",-1);
}
复制代码
2.2 方法参数的传递
概念: 方法的参数在传递的时候有一个特性:当传递的参数是基本数据类型的时候,代表复制传参,原值不会被改变,而传递的参数是引用数据类型的时候,代表引用传参,原值会发生改变。
public class 方法的参数传递 {
public static void main(String[] args) {
int a = 10;
fun1(a);
System.out.println(a);
int[] arrs = {1,2};
fun2(arrs);
System.out.println(Arrays.toString(arrs));
}
public static void fun1(int a){
a++;
}
public static void fun2(int[] a){
a[0]++;
}
}
复制代码
练习:
- 使用方法编程有什么好处?
- 静态方法可以访问非静态属性吗?
- 静态方法可以访问静态属性吗?
- 非静态方法可以访问静态属性吗?
- 非静态方法可以访问非静态属性吗?
- What is the result?
public class Batman {
int squares = 81;
public static void main(String[] args) {
new Batman().go();
}
void go() {
incr(++squares);
System.out.println(squares);
}
void incr(int squares) { squares += 10; }
}
复制代码
- A. 81
- B. 82
- C. 91
- D. 92
- E. Compilation fails.
- F. An exception is thrown at runtime.
- Click the Exhibit button. What is the output of the program shown in the exhibit?
- A. 300-100-100-100-100
- B. 300-300-100-100-100
- C. 300-300-300-100-100
- D. 300-300-300-300-100
2.3 方法的递归调用
概念:
- 递归的核心就一句话:自己调用自己。
- 递归虽然简单,比较耗时耗力,而且所有使用递归可以解决的问题,都能用循环来解决,所以不到万不得已的时候,不要使用递归。
- 递归必须要有出口!否则就是一个死递归。
源码: 死递归演示代码
@Test
public void test() {
fun();
}
public void fun() {
System.out.println("fun...");
fun();// 自己调用自己,会导致方法无限执行,最终堆栈溢出,抛出java.lang.StackOverflowError
}
复制代码
源码: 使用递归来求5的阶乘
@Test
public void testJC() {
int result = getJieCheng(5);
System.out.println(result);
}
private int getJieCheng(int num) {
// 第1次 num=5 return 5*getJieCheng(4) 待命
// 第2次 num=4 return 4*getJieCheng(3) 待命
// 第3次 num=3 return 3*getJieCheng(2) 待命
// 第4次 num=2 return 2*getJieCheng(1) 待命
// 第5次 num=1 return 1
if (num == 1)
return 1;// 出口
else
return num * getJieCheng(num - 1);
}
复制代码
[递归求阶乘过程描述]
案例:汉诺塔
@Test
public void testHanoi() {
hanoi(3, 'A', 'B', 'C');
}
// num 是一共有多少个盘子、a b c是三根柱子
private void hanoi(int num, char a, char b, char c) {
if (num == 1) {
System.out.printf("1号:%s >> %s\n", a, c);
} else {
// 无论多少盘子都分成两部分,num-1的上面的部分(看成一个盘子)和 最后一个盘子
int hanoiTopPart = num - 1;// 上面的盘子
hanoi(hanoiTopPart, a, c, b);// 将上面的盘子,从a途经c移到b
System.out.printf("%s号:%s >> %s\n", num, a, c);
hanoi(hanoiTopPart, b, a, c);// 将上面的盘子,再从b途经a移到c
}
}
复制代码
3. 初始化块
概念: JVM会在在创建一个类和使用这个类中间的时间里,执行初始化块里面的内容。初始化块包括构造方法、静态块和动态块。
3.1 构造方法
概念: 构造方法是一种特殊的方法,当我们实例化(new)一个类的时候,就是在调用这个类的构造方法的过程。每new一次,就会调用一次。
- 构造方法的名字必须和类名一致
- 构造方法没有返回值也不写void和return
- 构造方法不能被static等修饰
public class 构造方法 {
public static void main(String[] args) {
new A();
}
}
class A{
public A(){
System.out.println("我是A类的构造方法");
}
}
复制代码
3.2 构造方法分类
隐式无参构造方法 这种构造方法是一个类的默认构造方法,new一个类的时候默认调用这个方法 显式无参构造方法 自己在类中编写一个没有参数的构造方法,会覆盖掉隐式无参构造方法 显式有参构造方法 自己在类中编写一个有参数的构造方法这种构造器可以写多个,它们的共存要求是参数列表不相同new一个类的时候可以自动根据传进来的参数列表对应找到那个有参构造方法
tips:只要编写了显式的构造方法,隐式的构造方法就会失效。
public class 构造方法 {
public static void main(String[] args) {
new A();
new A("张三");
}
}
class A{
public A(){
System.out.println("我是A类的无参构造方法");
}
public A(String str){
System.out.println("我是A类的有参构造方法");
}
}
复制代码
3.2 动态块
概念: 动态块的格式就是"{...}",和构造方法一样,每new一次就会执行一次。不一样的是动态块必须全部执行,无法指定执行哪一个,而且执行顺序在构造器之前。
public class 动态块 {
public static void main(String[] args) {
new C();
}
}
class C{
public C(){
System.out.println(12);
}
{System.out.println("动态块1");}
{System.out.println("动态块2");}
}
复制代码
3.3 静态块
概念: 静态块的格式就是"static{...}",常用于一些初始化数据的工作。静态块和动态块不一样,它就只执行一次,而且执行顺序在动态块之前。静态块和静态方法一样,里面只能访问到静态的属性和方法。静态块和动态块必须全部执行,无法指定执行哪一个。
public class 静态块 {
public static void main(String[] args) {
new D();
}
}
class D{
public D(){
System.out.println("构造方法");
}
{
System.out.println("动态块");
}
static{
System.out.println("静态块");
}
}
复制代码
练习:
- Which two code fragments correctly create and initialize a static array of int elements? (Choose two.)
- A. static final int[] a = { 100,200 };
- B. static final int[] a; static { a=new int[2]; a[0]=100; a[1]=200; }
- C. static final int[] a = new int[2]{ 100,200 };
- D. static final int[] a; static void init() { a = new int[3]; a[0]=100; a[1]=200; }
- Which code should be inserted at line 1 of Demo.java to compile and run Demo to print "pizzapizza"?
package utils;
public class Repetition {
public static String twice(String s) { return s + s; }
}
// and given another class Demo:
// insert code here
public class Demo {
public static void main(String[] args) {
System.out.println(twice("pizza"));
}
}
复制代码
- A. import utils.*;
- B. static import utils.*;
- C. import utils.Repetition.*;
- D. static import utils.Repetition.*;
- E. import utils.Repetition.twice();
- F. import static utils.Repetition.twice;
- G. static import utils.Repetition.twice;
使用静态导入可以导入类中的所有静态域:import static 包路径.类名.*:导入这个类中所有的静态域
import static 包路径.类名.静态方法名:导入这个类中指定的静态方法。
4. this关键字
概念: java中提供this关键字,用法有两种
当类中某个非静态方法的参数名和类的某个成员变量名相同时,为了避免参数的作用范围覆盖了成员变量的作用范围,必须明确是使用this关键字来指定。
public class this关键字 {
public static void main(String[] args) {
String name = new F("张三").name;
System.out.println(name);
}
}
class F{
String name;
public F(String name){
this.name = name;
}
}
复制代码
"this."可以翻译成"当前类里的",如"this.name"就是"当前类里的name属性"。
如果某个构造方法的第一条语句具有形式this(...),那么这个构造方法将调用本类中的其他构造方法;
public class this关键字 {
public static void main(String[] args) {
String name = new F("张三").name;
System.out.println(name);
}
}
class F{
String name;
public F(String name){
this(12,name);
}
public F(int age,String name){
this.name = name;
System.out.println(name + ":" + age);
}
}
复制代码
tips:调用当前类里的其他构造器,只能写在当前构造器的第一行。
练习
- t01. this能用在静态方法中吗,this能用在静态块中吗?
5. 类的单一职责概念
在系统中,每个类都具有一定的职责,职责指的是类要完成什么样的功能,要承担什么样的义务。一个类可以有多种职责,设计得好的类一般只有一种职责。
在定义类的时候,将类的职责分解成为类的属性和操作(即方法),类的属性即类的数据职责,类的操作即类的行为职责。
设计类是面向对象设计中最重要的组成部分,也是最复杂和最耗时的部分。
6. 简单类
POJO、PO、DTO、DAO、BO、VO这些概念作为Java开发来说应该全部或者部分遇到过。
6.1 JavaBean
JavaBean是一种JAVA语言写成的可重用组件(就是指可以进行独立分离、易于重复使用的软件部分)。为写成JavaBean,类必须是具体的和公共的,并且具有无参数的构造器。
JavaBean必须满足的三个条件:
1. 实现Serializable接口(序列化就是将文件打碎成二进制,就是将对象状态转换为可保持或传输的格式的过程)
2. 提供无参数的构造器
3. 提供getter和setter方法访问它的属性
复制代码
理解:JavaBean就是一种简单的、可传输的java类。
public class JavaBean implements Serializable{
private String name;
private String gender;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
}
复制代码
6.2 POJO
概念: POJO(Plain Ordinary Java Object)简单的Java对象,POJO中有一些属性及其getter/setter方法的类,没有业务逻辑,当然,如果你有一个简单的运算属性也是可以的,但不允许有复杂的业务方法。当一个Pojo可序列化,有一个无参的构造函数,使用getter和setter方法来访问属性时,它就是一个JavaBean。
POJO一般用在数据层映射到数据库表的类,类的属性与表字段一一对应,等同于domain
public class POJO {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void printName(){
System.out.println(this.name);
}
}
复制代码
6.3 POJO分类
po Persistant Object 用在持久层,可以理解为POJO经过持久化后的对象 dto Data Transfer Object 据传输对象,一般用于向数据层外围提供仅需的数据,如查询一个表有50个字段,界面或服务只需要用到其中的10个字段,DTO就包装出去的对象,DTO可用于隐藏数据层字段定义,也可以提高系统性能,减少不必要字段的传输损耗 vo View Object 用在视图层,一般用于web层向view层封装并提供需要展现的数据 bo Business Object 用在service层,当业务比较复杂,用到比较多的业务对象时,可用BO类组合封装所有的对象一并传递,现在基本不用
tips:这些定义在实际使用设计中并不会全部用到,根据不同设计架构定义不同的类对象,形态大致如此,可根据自己项目进行调整。一般各层之间要尽量保持低耦合,不要相互依赖,如web尽量不要引用dao层或服务实现层中的类,在单应用中不会有问题,如果哪天做分布式部署,需要做重构,这些过度依赖将会是十分让人蛋疼的问题。