本博客主要对在JAVA学习过程的重点及难点信息进行总结,可能存在知识点不全的现象,如:Scanner类、String类、Math类等。如果大家有需要可以私聊博主,会发给大家详细的学习讲义,希望共同进步。
一、封装
1、Java语言是一种面向对象的程序设计语言,而面向对象思想是一种程序设计思想,我们在面向对象思想的指引下,使用Java语言去设计、开发计算机程序。 这里的对象泛指现实中一切事物,每种事物都具备自己的属性和行为。面 向对象思想就是在计算机程序设计过程中,参照现实中事物,将事物的属性特征、行为特征抽象出来,描述成计算 机事件的设计思想。它区别于面向过程思想,强调的是通过调用对象的行为来实现功能,而不是自己一步一步的去操作实现。
类:是一组相关属性和行为的集合。可以看成是一类事物的模板,使用事物的属性特征和行为特征来描述该 类事物。
属性:就是该事物的状态信息。
行为:就是该事物能够做什么。
类的定义格式:
public class ClassName {
//成员变量
//成员方法
}
2、面向对象编程语言是对客观世界的模拟,客观世界里成员变量都是隐藏在对象内部的,外界无法直接操作和修改。封装可以被认为是一个保护屏障,防止该类的代码和数据被其他类随意访问。要访问该类的数据,必须通过指定的 方式。适当的封装可以让代码更容易理解与维护,也加强了代码的安全性。
封装的步骤:
1)使用 private 关键字来修饰成员变量。
2)对需要访问的成员变量,提供对应的一对 getXxx 方法 、 setXxx 方法。
其中getXxx 方法:无参数,有返回值,可以理解为往外放,需要返回值。setXxx 方法:有参数,无返回值,可以理解为往里放,不用返回值。
public class Student {
private String name;
private int age;
public void setName(String n) {
name = n;
}
public String getName() {
return name;
}
public void setAge(int a) {
age = a;
}
public int getAge() {
return age;
}
}
当一个对象被创建时候,构造方法用来初始化该对象,给对象的成员变量赋初始值。
构造方法的定义格式:
修饰符 构造方法名(参数列表){
// 方法体
}
构造方法可分为两种:空参构造和有参构造,空参构造是系统自带的,括号里没有参数,有参构造括号里有参数。构造方法的写法上,方法名与它所在的类名相同。它没有返回值,所以不需要返回值类型,甚至不需要void。
二、继承
继承:就是子类继承父类的属性和行为,使得子类对象具有与父类相同的属性、相同的行为。子类可以直接 访问父类中的非私有的属性和行为。
好处:
1) 提高代码的复用性。
2)类与类之间产生了关系,是多态的前提。
子父类中出现了同名的成员变量时,在子类中需要访问父类中非私有成员变量时,需要使用 super 关键字,修饰 父类成员变量,类似于之前学过的 this 。
如果子类父类中出现不重名的成员方法,这时的调用是没有影响的。对象调用方法时,会先在子类中查找有没有对 应的方法,若子类中存在就会执行子类中的方法,若子类中不存在就会执行父类中相应的方法。
如果子类父类中出现重名的成员方法,这时的访问是一种特殊情况,叫做方法重写 (Override)。
方法重写 :子类中出现与父类一模一样的方法时(返回值类型,方法名和参数列表都相同),会出现覆盖效果,也称为重写或者复写。声明不变,重新实现。
重写的应用:子类可以根据需要,定义特定于自己的行为。既沿袭了父类的功能名称,又根据子类的需要重新实现父类方法,从 而进行扩展增强。比如新的手机增加来电显示头像的功能。
继承后的特点——构造方法
1)构造方法的名字是与类名一致的。所以子类是无法继承父类构造方法的。
2) 构造方法的作用是初始化成员变量的。所以子类的初始化过程中,必须先执行父类的初始化动作。子类的构 造方法中默认有一个 super() ,表示调用父类的构造方法,父类成员变量初始化后,才可以给子类使用。代码如下:
class Fu {
private int n;
Fu(){
System.out.println("Fu()");
}
}
class Zi extends Fu {
Zi(){
// super(),调用父类构造方法
super();
System.out.println("Zi()");
}
}public class Demo{
public static void main (String args[]){
Zi zi = new Zi();
}
}
输出结果:
Fu()
Zi()
继承实例,发红包:
群主发普通红包。某群有多名成员,群主给成员发普通红包。普通红包的规则:
1)群主的一笔金额,从群主余额中扣除,平均分成n等份,让成员领取。
2)成员领取红包后,保存到成员余额中。
案例分析:
案例代码:
package com.cp.demo.Demo1;
import java.util.ArrayList;
import java.util.Random;
public class Demo_HongBao {
public static void main(String[] args) {
Manager manager=new Manager("群主",100);
Member one=new Member("成员A",0);
Member two=new Member("成员A",0);
Member three=new Member("成员A",0);
manager.show();
one.show();
two.show();
three.show();
System.out.println("-----------");
//群主发了20元三个红包
ArrayList<Integer> redList =manager.send(20,3);
//三个普通成员收红包
one.receive(redList);
two.receive(redList);
three.receive(redList);
manager.show();
one.show();
two.show();
three.show();
}
}
class User{
private String name;//姓名
private int money;//余额,当前账户用于的钱
public User() {
}
public User(String name, int money) {
this.name = name;
this.money = money;
}
//显示当前用户有多少钱
public void show(){
System.out.println("我叫"+name+",我有"+money+"元钱");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getMoney() {
return money;
}
public void setMoney(int money) {
this.money = money;
}
}
//群主的类
class Manager extends User{
public Manager(){
}
public Manager(String name, int money) {
super(name, money);
}
public ArrayList<Integer> send(int totalMoney,int count){
//首先需要一个集合,来存储若干个红包的金额
ArrayList<Integer> redList=new ArrayList<>();
//首先看一下群主有多少钱
int leftMoney=super.getMoney();//群主当前的余额
if(totalMoney>leftMoney){
System.out.println("余额不足!");
return redList;//返回空集合
}
//扣钱,其实就是重新设置余额,super.setXX方法
super.setMoney(leftMoney-totalMoney);
//发红包,需要平均拆分为count份
int avg=totalMoney / count;
int mod=totalMoney % count; //余数,也就是甩下的零头
//剩下的零头,包在一个最后一个红包当中
//下面把红包一个一个放在集合当中
for (int i = 0; i < count-1; i++) {
redList.add(avg);
}
int last=avg+mod;
redList.add(last);
return redList;
}
}
//普通成员的类
class Member extends User{
public Member() {
}
public Member(String name, int money) {
super(name, money);
}
public void receive(ArrayList<Integer> list){
//从多个红包中随便抽取一个,给我自己
//随机获取一个集合中的索引编号
int index=new Random().nextInt(list.size());
//根据索引,从集合中删除,并且得到被删除的包,给我自己
int delta=list.remove(index);
//当前成员自己有多少钱
int money=super.getMoney();
//加法,重新设置回去
super.setMoney(money+delta);
}
}
三、多态
1、接口:是Java语言中一种引用类型,是方法的集合,如果说类的内部封装了成员变量、构造方法和成员方法,那么 接口的内部主要就是封装了方法,包含抽象方法(JDK 7及以前),默认方法和静态方法(JDK 8),私有方法 (JDK 9)。
接口的定义,它与定义类方式相似,但是使用 interface 关键字。它也会被编译成.class文件,但一定要明确它并 不是类,而是另外一种引用数据类型。接口可以多实现。
2、多态是继封装、继承之后,面向对象的第三大特性。 生活中,比如跑的动作,小猫、小狗和大象,跑起来是不一样的。再比如飞的动作,昆虫、鸟类和飞机,飞起来也 是不一样的。可见,同一行为,通过不同的事物,可以体现出来的不同的形态。多态,描述的就是这样的状态。
前提【重点】:
1)继承或者实现【二选一】
2)方法的重写【意义体现:不重写,无意义】
3)父类引用指向子类对象【格式体现】
多态的好处:实际开发的过程中,父类类型作为方法形式参数,传递子类对象给方法,进行方法的调用,更能体现出多态的扩展 性与便利。
代码如下:
//定义父类:
public abstract class Animal {
public abstract void eat();
}
//定义子类:
class Cat extends Animal {
public void eat() {
System.out.println("吃鱼");
}
}class Dog extends Animal {
public void eat() {
System.out.println("吃骨头");
}
}
//定义测试类:
public class Test {
public static void main(String[] args) {
// 多态形式,创建对象
Cat c = new Cat();
Dog d = new Dog();
// 调用showCatEat showCatEat(c);
// 调用showDogEat
showDogEat(d);
/*以上两个方法, 均可以被showAnimalEat(Animal a)方法所替代 而执行效果一致 */
showAnimalEat(c);
showAnimalEat(d);
}
public static void showCatEat (Cat c){
c.eat();
}
public static void showDogEat (Dog d){
d.eat();
}
public static void showAnimalEat (Animal a){
a.eat();
}
}
由于多态特性的支持,showAnimalEat方法的Animal类型,是Cat和Dog的父类类型,父类类型接收子类对象,当 然可以把Cat对象和Dog对象,传递给方法。 当eat方法执行时,多态规定,执行的是子类重写的方法,那么效果自然与showCatEat、showDogEat方法一致, 所以showAnimalEat完全可以替代以上两方法。 不仅仅是替代,在扩展性方面,无论之后再多的子类出现,我们都不需要编写showXxxEat方法了,直接使用 showAnimalEat都可以完成。 所以,多态的好处,体现在,可以使程序编写的更简单,并有良好的扩展。
四、String的不变性如何理解
字符串不变:字符串的值在创建后不能被更改。
以下面代码为例:
String s1 = "hello";
s1 += "word";
System.out.println(s1); // "helloword"
既然说String不可变,为什么hello后面连接word之后又变成helloword了,不是连接后还是hello吗?
实际上内存中有"hello",“helloword"两个对象,s1从指向"hello”,改变指向,指向了"helloword"。
五、static关键字的含义
关于 static 关键字的使用,它可以用来修饰的成员变量和成员方法,被修饰的成员是属于类的,而不是单单是属于某个对象的。也就是说,既然属于类,就可以不靠创建对象来调用了。
当 static 修饰成员变量时,该变量称为类变量。该类的每个对象都共享同一个类变量的值。任何对象都可以更改 该类变量的值,但也可以在不创建该类的对象的情况下对类变量进行操作。
比如说,基础班新班开班,学员报到。现在想为每一位新来报到的同学编学号(sid),从第一名同学开始,sid为 1,以此类推。学号必须是唯一的,连续的,并且与班级的人数相符,这样以便知道,要分配给下一名新同学的学 号是多少。这样我们就需要一个变量,与单独的每一个学生对象无关,而是与整个班级同学数量有关。 所以,我们可以这样定义一个静态变量numberOfStudent,代码如下:
public class Student {
private String name;
private int age;
// 学生的id
private int sid;
// 类变量,记录学生数量,分配学号
public static int numberOfStudent = 0;
public Student(String name, int age){
this.name = name;
this.age = age;
// 通过 numberOfStudent 给学生分配学号
this.sid = ++numberOfStudent;
}
// 打印属性值
public void show() {
System.out.println("Student : name=" + name + ", age=" + age + ", sid=" + sid );
}
}
public class StuDemo {
public static void main(String[] args) {
Student s1 = new Student("张三", 23);
Student s2 = new Student("李四", 24);
Student s3 = new Student("王五", 25);
Student s4 = new Student("赵六", 26);
s1.show(); // Student : name=张三, age=23, sid=1
s2.show(); // Student : name=李四, age=24, sid=2
s3.show(); // Student : name=王五, age=25, sid=3
s4.show(); // Student : name=赵六, age=26, sid=4
}
}
如果感兴趣可以再去掉public static int numberOfStudent = 0;中的static运行下看下结果有什么区别。