java基础(类与对象、集合)
类与对象
举例:
1.就拿英雄联盟或者王者荣耀来说
英雄这个统称我们叫做类
具体的哪个英雄我们称之为对象
2.做月饼
做月饼的模具我们可以称之为类
通过磨具做出来具体的月饼我们称之为对象
类和类中的对象都有一些共同的属性,对象是根据所在类的共同属性而做出来的
类是对象的模板,对象是类具体的一个实例
创建一个简单的类与对象:
类文件代码:
package OOPdemo;
public class Person {
// Person类所拥有的属性
String name;
int age;
// Person类所拥有的方法
public void eat(){
System.out.println("在吃饭");
}
public void study(){
System.out.println("在学习");
}
public void sleep(String place){
System.out.println("在"+place+"睡觉");
}
}
package OOPdemo;
public class Test1 {
public static void main(String[] args) {
// 创建一个zs的对象
Person zs = new Person();
// 给zs对象上绑定person类的属性
zs.name = "张三";
zs.age = 21;
zs.eat();
zs.study();
zs.sleep("寝室");
}
}
类与对象中的栈和堆
1.每个线程(调用一次main就会开启一个新的线程)会有单独的一个栈。每次调用方法,就会开启一个栈帧,方法结束以后栈帧弹出。先进后出。和垃圾回收机制没有关系。存放局部变量
2.堆内存中是共享的空间,不管多少线程,共享一块堆内存,对象中的内容都是存在堆内存中的。如果对象失去了指向,那么就会被垃圾回收。存放成员变量
构造方法
1.也叫做构造器
2.和类同名,不写返回值类型
3.完成对象的初始化操作
4.如果没有构造初始化方法,则系统会自动提供一个无参的构造方法
this关键字
this的作用:
1.每创建一个对象,都会产生一个this的引用变量,指向当前对象
2.在类的内部,可以通过this来访问类的成员
this的使用:
this.no = no;(调用成员变量,如果变量同名,则可以使用this来区分)
this(no, name);(调用构造方法,则需要放在方法内部的第一句)
面向对象三大特性
封装性(private)
访问权限修饰符:private、默认、protected、public
private:表示私有,只有自己类能够访问
默认:只有同一个包的类能够访问
protected:表示可以被同一个包的类和其他包的子类访问
public:表示可以被该项目的所有包中的类访问
类的属性的处理:
1.一般使用private访问权限
2.用封装的get、set方法来访问操作相关属性(注意:如果有传参的构造方法初始化传递的参数,则需要在构造方法中也使用set、get方法来对参数进行赋值)
类的处理:
1.类只能使用public和默认来进行修饰
2.默认:当前包
3.public:当前项目下的所有包
继承性(extends)
定义:继承可以让我们更加容易实现对类的扩展,比如说我们定义了动物类,那么哺乳动物就可以继承动物的公有属性或者方法(比如说都有名字、年龄、会说、会吃等等)
使用要点:
1.默认父类:Object
2.super:代表直接父类对象
3.this:指向对象本身
4.只有单继承
5.子类继承父类,可以得到父类的全部属性和方法,但不一定可以全部使用,因为可能会出现私有属性或方法
方法重写(@override)
背景:从父类继承下来的方法已经无法满足子类的需求了,这时我们可以考虑方法重写
public void introduce (){
super.introduce() ; //通过super调用父类的方法,这里可以选择不调用父类方法,完全自己重写
system.out.println (nickName) ;
}
注:
1.如果有修饰符final表示最后一个,则不能重写;如果是静态方法,则不能重写。
2.IDEA中alt+insert可以快速创建构造方法和set和get方法等等
多态性
多态指的是同一个方法调用,对象的不同会导致可能会有不同的行为,比如说,同样是吃饭,中国人是用筷子吃饭,而英国人使用刀叉吃饭
多态要点:
1.多态和成员变量无关,和重写的方法有关
2.无法调用子类特有的方法
3.多态的存在有3个必要条件(继承,方法的重写,父类引用指向子类对象)
4.父类引用指向子类对象后,用该父类调用子类重写的方法,此时多态就出现了
Programmer pro = new Chinese();//父类引用指向父类对象
pro.writeCode();
pro.eat();//多态,调用中国人的吃饭方法
向上转型(upcasting)
//引用数据类型的类型转换
Programmer pro = new Chinese();//此时是自动转换,向上转型,chinese向programer转型
pro.writeCode();//调用从父类继承的方法,结果是唯一的
pro.eat();//调用被子类重写的方法,结果是子类的结果
向下转型(downcasting)
将父类的引用变量转换成子类的类型,叫做向下转型,向下转型后就可以调用子类特有的方法。
1.需要进行强制转换
2.跟基本数据类型向下转换不同,基本数据类型强制向下转换相当于“做手术”。引用类型强制转换不能“做手术”,必须转化为真实的子类类型
//引用数据类型的类型转换
Programmer pro = new Chinese();
pro.eat();
//pro.playBoxing();***不能直接使用子类特有的方法
Chinese ch =(Chinese)pro; //向下强制转换
ch.playBoxing() ; //此时可以调用子类特有的方法
注:在类的继承树关系上,必须要有上下级关系
简单工厂模式
工厂负责创建,使用者直接调用;
基本要求:
1.定义一个static方法,可以直接通过类名调用
2.传入一个字符串类型的参数,工厂根据参数创建相应的对象(子类产品)
final关键字
作用:
1.修饰变量:被修饰后不能被改变,一旦被赋值,就不能重新赋值
final a = 100;
2.修饰方法:不能被重写,但可以被重载
final void look(){}
3.修饰类:被修饰的类不能被继承
final class A{}
注意:
1.不能修饰构造方法
2.修饰基本数据类型,只能赋值一次
3.修饰引用数据类型时,比如:
final Cat cat = new Cat();
不能变的是cat这个对象的引用地址,其内部的属性还是可以发生改变的
抽象类
比如说我们创建动物类的时候,有时候不希望这个动物类不被new成一个实例对象,就可以在类之前加上一个abstract(抽象的),就可以防止被new出一个新Animal
Animal类
public abstract class Animal {
private String name;
private int age;
// 无参构造方法
public Animal() {
}
// 有参构造方法
public Animal(String name, int age) {
this.name = name;
this.age = age;
}
}
主类
public static void main(String[] args) {
// Animal an = new Animal(); 会报错,因为Animal是抽象类
}
扩充:抽象方法:
Animal类:
public abstract void look();/*{
System.out.println("----动物在看----");
}*/
特点:没有方法体,告诉子类必须给抽象方法具体的实现,否则会报错
Dog类:
public void look(){
System.out.println("---animal look---");
}
接口
背景:
比如说多种事物都有同样的功能,比如人和爬行动物都有吃的功能,但他们的父类都不是同一个,此时就可以使用接口来实现
定义:
1.接口定义的是一种规范,一组规则
2.接口中定义的全是全局静态final常量
3.接口不能new,也没有构造方法,不会自动继承类
4.接口中所有的方法都是抽象的
5.接口之间用的是继承(extends)
6.接口与类之间用的是实现(implements)实现接口中的规范
接口中定义一个常量:
public static final int age;
// 接口中下面这种的定义方式的性质其实就是上面这种
int age;
注:既有继承又有实现的话,先写继承extends再写实现implements
最后还有异常和常用类,做实际项目时都会接触到的,建议多敲代码,这两个就很好理解
集合
ArrayList
// 创建一个ArrayList对象
ArrayList arr = new ArrayList();
// 向ArrayList中添加元素
arr.add(80);//在末尾添加一个元素
arr.add(69);//自动装箱
arr.add(68);//集合的元素必须是对象类型
arr.add(1, 100);//指定位置添加数据
// 获取ArrayList的数据
System.out.println("---------------------------");
System.out.println(arr);
System.out.println(arr.size());//获取元素个数
System.out.println(arr.get(1));//获取索引对应元素
// 遍历arr
System.out.println("---------------------------");
// 1、
for (int i = 0; i < arr.size(); i++) {
int arrs = (int)arr.get(i);
System.out.println(arrs);
}
System.out.println("-------------------------------");
// 2、使用迭代器遍历
Iterator it = arr.iterator();
while (it.hasNext()){
int its = (int)it.next();
System.out.println(its);
}
缺点:
1.遍历得到的数据类型是对象,需要强制转换
2.添加字符串类型数据不安全
解决办法(**
泛型
**(jdk1.5))(数据安全,不需要强制转换):
// 创建一个ArrayList对象
ArrayList<Integer> arr = new ArrayList<Integer>();
// 2、使用迭代器遍历
Iterator<Integer> it = arr.iterator();
其他方法:
// 删除方法:
arr.clear();//全部删除
arr.remove(new Integer(80));//删除内容为80的元素
arr.remove(1);//删除索引为1的元素
// 修改方法:
arr.set(0,99);
LinkedList
和ArrayList使用方法基本相同
相对于ArrayList提供了更多的方法
不同的地方:
1.底层的存储结构发生改变
ArrayList:数组
LinkedList:双向链表
2.方法底层的实现(比如在指定位置添加元素)
ArrayList:后移元素 效率较低
LinkedList:修改前后节点指针 效率较高
使用哪种集合根据情况而定:
如果是添加删除元素 LinkedList
如果是按照索引查询元素 ArrayList
Set集合
Set <String>se = new <String>HashSet();
se.add("HTML");
se.add("CSS");
se.add("Javascript");
se.add("HTML");//不接受重复数据
System.out.println(se.size());//3
System.out.println(se.toString());//[CSS, Javascript, HTML]
HashSet:唯一、无序
Set <String>se = new <String>LinkedHashSet();
se.add("HTML");
se.add("CSS");
se.add("Javascript");
se.add("HTML");//不接受重复数据
System.out.println(se.size());//3
System.out.println(se.toString());//[HTML, CSS, Javascript]
LinkedHashSet:唯一、有序(添加顺序)
Set <String>se = new <String>TreeSet();
se.add("HTML");
se.add("CSS");
se.add("Javascript");
se.add("HTML");//不接受重复数据
System.out.println(se.size());//3
System.out.println(se.toString());//[CSS, HTML, Javascript]
TreeSet:唯一、有序(自然顺序)、红黑树(从小到大)
遍历方法(foreach、迭代)
// 两种遍历方法
// 1.foreach
for (String ele:se
) {
System.out.println(ele);
}
// 2.迭代
Iterator<String> it = se.iterator();
while (it.hasNext()){
String ele = it.next();
System.out.println(ele);
}
哈希表
哈希表中添加数据步骤:
1.计算哈希码
x=key.hashCode();
2.根据哈希码计算存储的位置
y=x%11;
3.存入指定的位置
情况一、如果是空链表:直接添加一个节点
情况二、如果不是空(数据不相同):调用equals进行比较,如果没有相同的内容,则添加到节点中
情况三、如果不是空(数据相同):调用equals进行比较,如果有相同的内容,则不再添加,确保了数据的唯一性
哈希表的查询和添加顺序是一样的
Map
特点:key唯一、无序
创建方法和Set类似,不过要注意的是使用泛型时要指定key和value的数据类型
添加数据用put方法
HashMap:
//创建一个map对象
Map<String,String> map = new HashMap<String,String>();
//向map对象中添加数据
map.put("cn","China");
map.put("jp","Japen");
// 查看数据
System.out.println(map);//{jp=Japen, cn=China}
System.out.println(map.size());//2
key:唯一、无序、HashSet特点
value:不唯一、无序
LinkedHashMap:
//创建一个map对象
Map<String,String> map = new LinkedHashMap<String,String>();
//向map对象中添加数据
map.put("cn","China");
map.put("jp","Japen");
// 查看数据
System.out.println(map);//{cn=China, jp=Japen}
System.out.println(map.size());//2
key:唯一、有序(添加顺序)、LinkedHashSet特点
value:不唯一、无序
TreeMap:
key:唯一、有序(自然顺序)、TreeSet特点、不能添加空元素
value:不唯一、无序
Map常用操作:
创建对象、添加数据、根据key查找数据
遍历:
//通历2∶得到所有的key-value组成的set,直接逼历Set 推荐使用
Set<Map.Entry<String,String>> entrySet = map.entrySet();
for (Map.Entry<String,String> entry:entrySet){
// System.out.println (entry) ;
System.out.println (entry.getKey() +"====>>"+entry.getValue());
}