方法的递归调用 熟练
在编程语言中, 递归指的是一个运算过程 , 说的是, 方法不断调用自身 , 直到运算的结果已知 !
递归的好处:
递归可以大幅度的简化代码 !
缺点:
在可以使用循环的案例中, 建议不要使用递归 !
递归极易造成 栈内存溢出(StackOverflowError)的问题 !
为了避免递归的缺点, 使用原则:
1. 递归必须有退出的条件(出口)
2. 在使用递归时, 一定是把问题变得简单了, 而不是因为使用递归显得复杂了 !
需求:
递归实现阶乘:
计算5的阶乘
1*2*3*4*5
public static int haha(int n){
if(n==1){
return 1;
}
return n*haha(n-1);
}
//120
public static int haha(int 5){
if(5==1){
return 1;
}
return 5*haha(5-1);
}
haha(5-1): 24
public static int haha(int 4){
if(4==1){
return 1;
}
return 4*haha(4-1);
}
haha(4-1): 6
public static int haha(int 3){
if(3==1){
return 1;
}
return 3*haha(3-1);
}
haha(3-1): 2
public static int haha(int 2){
if(2==1){
return 1;
}
return 2*haha(2-1);
}
haha(2-1): 1
public static int haha(int 1){
if(1==1){
return 1;
}
return 2*haha(2-1);
}
封装,私有 重点
在说封装之前, 先观察如下代码:
public class Demo3{
public static void main(String[] args){
Person p = new Person();
p.name = “董飞”;
p.age = -18;
p.say();
}
}
class Person{
String name;
int age;
void say(){
System.out.println(“我是:”+this.name+”,我今年”+this.age+”岁了”);
}
}
上述的程序 输出的结果为: 我是:董飞,我今年-18岁了
上述的程序, 并不存在语法错误 , 但是出现了逻辑问题, 年龄小于了!
为了避免我们在调用时, 传递的错误数据的问题 , 可以尽量的避免自己直接触碰对象中的属性:
public class Demo4{
public static void main(String[] args){
Person p = new Person();
p.setName(“董飞”);
p.setAge(18);
p.say();
}
}
class Person{
String name;
int age;
void setName(String name){
this.name = name;
}
void setAge(int age){
if(age<1||age>120){
System.out.println("因为数据超出了范围, 所以设置为了1岁");
this.age = 1;
}else{
this.age = age;
}
}
void say(){
System.out.println("我是:"+this.name+",我今年"+this.age+"岁了");
}
}
上述的案例, 解决了逻辑问题的产生, 但是并不能阻止别人通过对象.属性去访问age , 接下来通过封装, 让外部找不到age属性 !
封装的实现(private)
public class Demo4{
public static void main(String[] args){
Person p = new Person();
p.setName(“董飞”);
//p.setAge(-18);
p.age = -18;
p.say();
}
}
class Person{
private String name;
private int age;
void setName(String name){
this.name = name;
}
void setAge(int age){
if(age<1||age>120){
System.out.println("因为数据超出了范围, 所以设置为了1岁");
this.age = 1;
}else{
this.age = age;
}
}
void say(){
System.out.println("我是:"+this.name+",我今年"+this.age+"岁了");
}
}
封装的总结
封装可以避免很多的逻辑BUG ,
封装的关键字: private , 可以用来修饰成员属性 和 成员方法, 修饰过的成员, 只能在当前类中直接访问 !
编程规范:
1. 如果属性不是常量, 必须私有private , 确保外部的调用者无法直接赋值!
2. 需要根据封装的属性, 提供供外部间接访问的方法 (读/写)
- 获取属性的方法规范:
返回值类型与属性类型相同 , 方法名称为:
get属性名, 并且属性名称首字母大写
例如:
String getName(){
return this.name;
}
int getAge(){
return this.age
}
- 设置属性的方法规范:
没有返回值, 形式参数列表, 需要一个与属性相同名称, 相同类型的参数 ! 方法名称为set属性名, 属性名称首字母大写
例如:
void setName(String name){
this.name = name;
}
void setAge(int age){
this.age=age;
}
3. 再构造方法中 , 也建议通过setXXX进行赋值 !
封装学习完毕后, 设计一个Person类
Bean类 (模型类,基本类)
1. 所有的属性, 必须私有
2. 必须存在无参构造器
3. 所有的私有属性, 必须存在set与get方法
class Person{
private String name;
private int age;
private char sex;
//构造方法
Person(){}
Person(String name,int age,char sex){
this.setName(name);
this.setAge(age);
this.setSex(sex);
}
//get与set方法
void setName(String name){
this.name = name;
}
String getName(){
return this.name;
}
void setAge(int age){// p.age = xxx;
this.age = age;
}
int getAge(){//p.age
return this.age;
}
void setSex(char sex){
this.sex = sex;
}
char getSex(){
return this.sex;
}
}
Person p = new Person();
Person p2 = new Person();
static静态 重点
静态修饰的方法和属性, 在类加载时, 就存在方法区了!
而未通过静态修饰的方法或属性, 依赖于对象, 对象创建时, 方法和属性才可以使用!
静态是依赖于类的, 类加载时, 静态的属性与方法就加载到了方法区 !
无论存在多少个对象 , 静态的方法/属性, 永远在内存中只有一份(所有对象公用)
静态不能访问非静态 , 非静态可以访问静态 !
静态:
1. 静态方法中
2. 静态代码块中
3. 静态属性
4. .. 静态内部类
很容易编写代码时. 违反规则的非静态内容:
1. 在静态方法中 给 非静态属性赋值 !
2. 在静态方法中 使用 this关键字
静态属性, 属于对象共有的案例:
class Person{
static String city;
private String name;
private int age;
void setName(String name){
this.name = name;
}
String getName(){
return this.name;
}
void setAge(int age){
this.age = age;
}
int getAge(){
return this.age;
}
void say(){
System.out.println(“我是”+name+”,我今年”+age+”岁了,我来自”+city);
}
}
代码块 熟练掌握
代码块优先级:
静态代码块 –> 构造代码块 –> 构造方法
Java中 {} , 大括号 中属于代码块
之前我们编写过类的代码块 , 方法的代码块, 构造方法的代码块
class XX{
}
void say(){
}
Person(){
}
构造块:
类似构造方法(构造器) , 每次创建对象, 构造块都会执行!
编写的方式: 在类中 直接编写代码块 (成员位置) ! 可以编写多个 !
构造块 , 每次创建对象, 构造块都会执行!
一般我们在构造块中, 完成一些对象初始化的操作 !
this 表示新创建的对象 !
例如:
class Person{
{//
}
private String name;
private int age;
get/set...
}
案例:
记录一个类 创建了几个对象:
public class Demo8{
public static void main(String[] args){
Person p1 = new Person();
Person p2 = new Person();
Person p33 = new Person();
Person p3 = new Person();
Person p44 = new Person();
Person p5 = new Person();
Person p6 = new Person();
Person p7 = new Person();
Person p77 = new Person();
Person p777 = new Person();
Person p888 = new Person();
Person p8 = new Person();
Person p88 = new Person();
Person p12 = new Person();
Person p13 = new Person();
Person p15 = new Person();
System.out.println("Person类一共创建了"+Person.count+"次对象");
}
}
class Person{
private String name;
private int age;
static int count = 0;
Person(){
count++;
}
Person(String name,int age){
this.name = name ;
this.age = age;
count++;
}
}
静态代码块:
语法:
与构造块 编写基本相同, 只需要再大括号的开始, 添加static关键字即可:
静态块什么时候执行:
类加载时, 静态块就会执行 , 并且只会执行一次 !
作用:
用来给类中的(static)信息进行初始化!
例如:
class Person{
static int count = 0;
static{
//使用20行代码 ! 查询上次关闭时保存的数量
}
}
普通代码块:
就是很普通的给代码分区域:
再可执行的代码位置, 编写大括号
{
}
案例:
class Demo{
public static void main(String[] args){
{//普通代码块
}
{//普通代码块
}
}
}
单例设计模式(重点)
单例: 一个类只有单个实例!
如果构造方法可以被调用, 则可以被创建多个对象
解决方案: 构造方法私有化 (使用private修饰)
因为构造方法被私有, 只有在类的内部才可以创建对象 , 在类的内部, 私有一个静态的类对象的引用!
向外部提供一个可以获取这个对象的方法
单例设计模式
- 实现1. 饿汉式
class Single{
private Single(){}
private static Single s = new Single();
static Single getInstance(){
return s;
}
}
- 实现2. 懒汉式
class Single{
private Single(){}
private static Single s;
static Single getInstance(){
if(s==null){
s= new Single();
}
return s;
}
}
懒汉单例 与 饿汉单例的区别:
饿汉是在类加载时, 就创建了对象, 等待调用方法返回这个对象 !
懒汉在类加载时, 并未创建对象, 在第一次调用获取方法时, 进行了对象的创建 !
继承 重点
继承发生在类与类或接口与接口之间 !
Java语言不支持多继承,但是支持多重继承,一个类只能继承一个父类。但一个父类可以有多个子类。
Student继承自Person的案例:
人的特征:
年龄, 姓名
人的行为:
说话
学生的特征:
年龄, 姓名, 学号, 学校信息
学生的行为:
说话, 学习 !
人:
class Person{
private int age;
private String name;
Person(int age,String name){
this.age = age;
this.name = name;
}
void setAge(int age){
this.age = age;
}
int getAge(){
return this.age;
}
void setName(String name){
this.name = name;
}
String getName(){
return this.name;
}
void say(){
System.out.println("我是:"+name+",我今年"+age+"岁了");
}
}
//学生
class Student extends Person{
Student(){
super(0,null);
}
//学号
private int id;
//学校
private String school;
void setId(int id){
this.id = id;
}
int getId(){
return this.id;
}
void setSchool(String school){
this.school = school;
}
String getSchool(){
return this.school;
}
void learn(){
System.out.println("我的学号是:"+id+",我来自"+school);
}
}
构造方法
子类的构造方法中 隐式的调用了 父类的无参构造器 !
调用父类的构造器的原因在于, 需要创建属于父类的属性 !
我们可以显式的指定具体调用的父类构造方法!
super表示当前对象的 父类对象的引用!
Eclipse下载
打开官网下载安装包: eclipse.org
解压使用(路径不可以出现中文)
jvm找不到
1. jdk版本与eclipse不一致!
2. jdk位数与eclipse不一致,例如: 32位的jdk 64位的eclipse