三元运算符
Scanner scanner = new Scanner(System.in);
System.out.println("请输入第一个数字:");
int a = scanner.nextInt();
System.out.println("请输入第二个数字:");
int b = scanner.nextInt();
System.out.println("请输入第三个数字:");
int c = scanner.nextInt();
System.out.println("下面输出上述的最大值,请稍等");
int temp =a>b?a:b;
int max = c>temp?c:temp;
System.out.println(max);
switch判断
public static void main(String[] args) {
int a = 10;
switch (a){
case 1:
System.out.println("111111");
break;
case 2:
System.out.println("22222222");
break;
case 10:
System.out.println("ni");
break;
default:
System.out.println("33333");
break;
}
}
匿名对象,所谓的匿名对象就是左边没有名字和赋值运算符,只有右边对象。
循环
计算水仙花数经典案例
public class ShuiXianHua {
//计算水仙花数
public static void main(String[] args) {
int d = 0;
for (int i = 100; i < 1000; i++) {
int a = i%10;
int b = i/10%10;
int c = i/100;
if (a * a * a + b * b * b + c * c * c == a + b * 10 + c * 100){
d++;
System.out.println(i); //输出水仙花类型
}
}
System.out.println(d); //输出符合水仙花的数值的总数
}
}
do…while循环,不管是否符合判断条件,都会执行一次
public class Demo01dowhile {
public static void main(String[] args) {
int a = 10;
do {
System.out.println(a);
a++;
}while (a<9);
}
}
增强for循环。for循环中的变量类型需要和数组元素类型一致
public static void main(String[] args) {
String[] str1 ={"123", "234", "e43"};
for (String s : str1) {
System.out.println(s);
}
}
}
java中单引号和双引号的区别:
单引号中是字符,双引号中是字符串
System.out.println("H"+"A"); //HA 拼接为HA字符串
System.out.println('H'+'a'); //169 H和a进行了加法运算2) 根据ASCII表H = 72和a = 97
构造方法是一种特殊的方法,作用就是创建对象。功能:主要完成对象数据的初始化
方法重载Overload(方法的名称一样,参数的列表不一样):
1.多个方法在同一个类中
2.参数个数不同
3.参数类型不同
4.参数类型顺序不同
方法的重写(覆写、覆盖)Override
重写发生在继承关系中,方法的名称一样,参数列表也一样。
特点:创建的是子类对象,则优先用子类的方法。
子类方法的返回值必须小于等于父类方法的返回值范围。
子类方法的权限必须大于等于父类方法的权限
例子
public class Phone {
public void call(){
System.out.println("打电话");
}
public void send(){
System.out.println("发短信");
}
public void show(){
System.out.println("显示号码");
}
}
public class NewPhone extends Phone {
@Override
public void show(){
super.show(); //super关键字
System.out.println("显示头像");
System.out.println("显示姓名");
}
}
public class DemoPhone {
public static void main(String[] args) {
Phone phone = new Phone();
phone.show();
phone.call();
phone.send();
System.out.println("================================");
NewPhone newPhone = new NewPhone();
newPhone.show();
newPhone.call();
newPhone.send();
}
结果:
显示号码
打电话
发短信
================================
显示号码
显示头像
显示姓名
打电话
发短信
数组:
数组反转案例
public class ArrReverse {
public static void main(String[] args) {
int[] arr = {18,23,34,667,564,1};
for (int start = 0,end=arr.length-1; start <=end; start++,end--) {
int temp = arr[start];
arr[start] = arr[end];
arr[end] =temp;
}
printArray(arr);
}
public static void printArray(int[] arr){
System.out.print("[");
for (int x = 0; x <arr.length ; x++) {
if (x == arr.length - 1){
System.out.print(arr[x]);
}else {
System.out.print(arr[x]+",");
}
}
System.out.print("]");
}
}
public class Score {
//需求:在编程竞赛中,有6个评委为参赛的选手打分,分数为0-100的整数分。
//选手的最后得分为,去掉一个最高分和最低分之后剩下的4个平均值。
public static int[] getScore() {
int[] arrScore = new int[6];
Scanner scanner = new Scanner(System.in);
for (int i = 0; i < 6; i++) {
System.out.println("请输入第"+(i+1)+"个评委的打分:");
arrScore[i] = scanner.nextInt();
}
System.out.print("[");
for (int i = 0; i < arrScore.length; i++) {
if (i < arrScore.length - 1) {
System.out.print(arrScore[i] + ",");
} else {
System.out.print(arrScore[i] + "]");
}
}
return arrScore;
}
//定义一个方法,得到数组中的最高分
public static int getMaxScore(int[] arr) {
int max = arr[0];
for (int i = 0; i < arr.length; i++) {
if (arr[i]>max){
max = arr[i];
}
}
return max;
}
//定义一个方法,得到数组中的最低分
public static int getMinScore(int[] arr){
int min = arr[0];
for (int i = 0; i <arr.length ; i++) {
if (arr[i]<min){
min=arr[i];
}
}
return min;
}
//定义一个方法获取数组的平均分
public static int getAvgScroe(int[] arr){
int sum = 0;
int a = 0;
for (int i = 0; i <arr.length ; i++) {
int minScore = getMinScore(arr);
int maxScore = getMaxScore(arr);
if (arr[i]==minScore||arr[i]==maxScore){
sum = sum+0;
a = a+0;
}else {
sum = sum+arr[i];
a = a+1;
}
}
int avg = sum/a;
return avg;
}
public static void main(String[] args) {
int avg = getAvgScroe(getScore());
System.out.println("------------------------");
System.out.println(avg);
}
}
关于ArrayList:
1.ArrayList 类是一个可以动态修改的数组,与普通数组的区别就是它是没有固定大小的限制,我们可以添加或删除元素
2.常用例子
public class Demo05ArrayList {
public static void main(String[] args) {
ArrayList<Integer> arrayList = new ArrayList<>();
arrayList.add(1);
arrayList.add(2);
arrayList.add(3);
System.out.println(arrayList);
// arrayList.remove(1); //remove(索引值)
System.out.println(arrayList);
arrayList.get(1); //get(索引值)
System.out.println(arrayList);
}
}
字符串String
1.字符串的截取:左闭右开,substring(1,3)。括号中是索引值
2.统计不同类型字符出现次数经典案例
/**
* 键盘输入一个字符串,并且统计其中各种字符出现的次数
* 种类有:大写字母、小写字母、数字、其他
* 思路:1.键盘输入,sc.next()
* 2.String类型转换为字符串,toCharArray()
* 3.
*/
public class Demo07StringCount {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.println("请输入一个字符串:");
String str = scanner.next();
char[] array = str.toCharArray();//输出的是字符数组
int countUpper = 0;
int countLower = 0;
int countNum = 0;
int countOther = 0;
for (int i = 0; i < array.length; i++) {
if ('A'<=array[i]&&array[i]<='Z'){
countUpper++;
}else if ('a'<=array[i]&&array[i]<='z'){
countLower++;
}else if ('0'<=array[i]&&array[i]<='9'){
countNum++;
}else{
countOther++;
}
}
System.out.println("大写字母的个数是:"+countUpper);
System.out.println("小写字母的个数是:"+countLower);
System.out.println("数字个数是:"+countNum);
System.out.println("其他个数是:"+countOther);
}
}
//把随机字符串中的所有字符升序排列,并倒序打印
public class Demo02Arrays {
public static void main(String[] args) {
String s1 = "12ewra434f是我";
char[] chars = s1.toCharArray();
Arrays.sort(chars);
// System.out.println(chars);
for (int i = chars.length - 1; i >= 0; i--) {
System.out.println(chars[i]);
}
}
}
将字符串对象中的字符转换为一个字符数组
String和StringBuilder的区别:
String:内容是不可变的
StringBuilder:内容是可变的
String和StringBuilder之间的相互转换方法:
//将String类型的字符串转换成StringBuilder类型,使用StringBulider构造方法
String s = "hello";
StringBuilder sb = new StringBuilder(s);
System.out.println(s);
//将StringBuilder类型的字符串转换成String类型,使用toString方法即可
StringBuilder sb1 = new StringBuilder();
sb1.append("world");
String s1 = sb1.toString();
System.out.println(s1);
Math工具类的使用
//计算-10.8到5.9之间,绝对值大于6或者小于2.1的整数有多少个?
public class DemoMath01 {
public static void main(String[] args) {
double min = -10.8;
double max = 5.9;
int count = 0;
for (int i = (int) min; i <max ; i++) {
if (Math.abs(i)>6 || Math.abs(i)<2.1){
count++;
}
}
System.out.println(count);
}
}
静态static关键字描述
一旦使用了static关键字,那么这样的内容就不再属于自己,而是属于类的,所以凡是本类的对象,都共享同一份。
public class Person {
static {
System.out.println("静态代码块执行!!!");
}
public Person(){
System.out.println("构造方法执行!");
}
}
public class Demo04Static {
public static void main(String[] args) {
Person p1 = new Person();
Person p2 = new Person();
Person p3 = new Person();
}
}
执行结果如下:
静态代码块执行!!!
构造方法执行!
构造方法执行!
构造方法执行!
静态代码块仅会执行一次。
静态不能直接访问非静态。原因:因为在内存中先有的静态内容,后有的非静态内容。“先人不知道后人,但是后人知道先人”。
静态不能使用this。因为静态针对的是类,而不是具体的某一个对象
public class Student {
private String name;
private int age;
private int id;
private static int idCounter = 0; //可以作为学号计数器,每当new了一个对象的时候,计数器++
public Student() {
idCounter++;
}
public Student(String name, int age) {
this.name = name;
this.age = age;
this.id = ++idCounter;
}
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 static void main(String[] args) {
Student student01 = new Student("cui", 12);
Student student02 = new Student("li", 15);
System.out.println("学生1的姓名:" + student01.getName() + ";"
+ "学生1的年龄:" + student01.getAge() + ";"
+ "学生1的学号:" + student01.id);
System.out.println("学生2的姓名:" + student02.getName() + ";"
+ "学生2的年龄:" + student02.getAge() + ";"
+ "学生2的学号:" + student02.id);
}
}
运行结果:
学生1的姓名:cui;学生1的年龄:12;学生1的学号:1
学生2的姓名:li;学生2的年龄:15;学生2的学号:2
区分子类方法中重名的三种变量
super关键字的使用
1.在子类的成员方法中,访问父类的成员变量。
super.num;
2.在子类的成员方法中,访问父类的成员方法。
super.method();
3.在子类的构造方法中,访问父类的构造方法。
public Zi(){
super();
}
this关键字的三种用法
this关键字是用来访问本类内容
1.在本类的方法中访问本类的成员变量
2、在本类的方法中访问本类的另一个成员方法
3、在本类的构造方法中访问本类的另一个构造方法
public class Zi extends Fu {
int num = 10;
public Zi(){
this(20); //在本类的构造方法中,访问本类的另一个构造方法。本类的无参构造,调用本类的有参构造
}
public Zi(int num){
}
public void showNum(){
int num = 20;
System.out.println(num); //输出局部变量20
System.out.println(this.num); //输出本类的成员变量10
System.out.println(super.num); //输出父类的成员变量6
}
public void methodA(){
System.out.println("AAA");
}
public void methodB(){
this.methodA();//在本类的成员方法中,访问本类的另一个成员方法
System.out.println("BBB");
}
}
抽象
抽象方法:就是在返回值之前加上abstract关键字,去掉大括号,直接分号结束。
抽象类:抽象方法所在的类必须是抽象类,就是在class之前加上abstract关键字。
public abstract class DemoAbstract01 {
// 这是一个抽象方法,代表吃东西,但是具体吃的是什么东西(大括号里的内容)不确定
public abstract void eat();
}
如何使用抽象方法和抽象类:
1、不能直接创建new抽象对象;
2、需要子类继承抽象父类;
3、子类需要覆盖重写父类当中所有的抽象方法。
覆盖重写:去掉abstract关键字,补上大括号
public abstract class Animal {
public abstract void eat();
}
public class Cat extends Animal {
@Override
public void eat() {
System.out.println("猫吃鱼,狗吃肉,奥特曼打小怪兽");
}
}
抽象类是对事物的抽象,接口是对行为的抽象。
接口相关知识
接口的抽象方法定义如下:
/**
* 注意事项:接口当中的抽象方法,修饰符必须是两个固定的关键字,public和abstract
* 这两个关键字修饰符,可以选择性的忽略
*/
public interface DemoInterface {
// 以下都是抽象方法
public abstract void methods0();
public void methods1();
abstract void methods2();
void methods3();
}
接口的使用步骤:
1.接口不能直接使用,必须有一个实现类来实现该接口
格式:
public class 实现类名 implements 接口名称{
//……………………
}
2.接口的实现类必须覆盖重写(实现)接口中的所有抽象方法,除非实现类是抽象类;
实现:去掉abstract关键字,加上大括号
3.创建实现类的对象,进行使用。
注意事项:不能通过接口实现类的对象来调用接口当中的静态方法。正确方法是直接通过接口名.静态方法名(参数)
4.在java 9+的版本中,成员变量(其实就是常量)的定义如下:
public static final 数据类型 常量名称=值 ;常量名称必须是大写字母,多个需要下划线分割
例子:public static final int NUM_MY_AGE = 26;
5.接口中最重要的就是抽象方法
public abstract void method01(参数列表){
//方法体
}
6.从java8开始,接口里允许定义默认方法,格式是:
public default 返回值类型 方法名(参数列表){
//方法体
}
7.从java8开始,接口里允许定义静态方法,格式:
public static 返回值类型 方法名称(参数列表){
//方法体
}
注意:应该通过接口名称调用,不能通过实现类对象调用接口静态方法。
8.从java9开始,接口中允许定义私有方法。只有接口自己才可以调用,不能被实现或被别人使用
9.接口没有静态代码块或构造方法。
10、一个类的直接父类是唯一的,但是一个类可以同时实现多个接口。
public class MyInterfaceImpl implements MyInterfaceA,MyInterfaceB{
}
多态
父类引用指向子类对象就叫做多态。
格式:父类名称 对象名 = new 子类名称();
或者:接口名称 对象名 = new 实现类名称();
访问成员变量的两种方式:
1、直接通过对象名称访问成员变量,看等号左边是谁,优先用谁,没有就向上找。
2、间接通过成员方法访问成员变量,看该方法属于谁, 优先用谁,没有就向上找。
成员变量:编译看左,运行看左
System.out.println(cat1.age);//age的取值是看父类中age的取值
在多态当中成员方法的访问规则是:
编译看左,运行看右
System.out.println(cat1.eat());//看父类中有没有eat()方法,运行是看子类中eat()方法内容
对象的向上转型其实就是多态写法:
Animal animal = new Cat();
含义:右侧创建了一个子类对象,把它当做父类来看待。创建了一只猫,把这猫当动物。
多态
多态:
1、有继承或实现关系
2、方法重写
3、父类引用指向子类对象
多态中成员访问特点
1、访问成员变量:编译看左,运行看左
2、访问成员方法:编译看左,运行看右
多态的好处和弊端
1、提高了程序的扩展功能
具体的体现:定义方法的时候,使用父类型作为参数,将来在使用的时候,使用具体的子类型参与操作
2、但是不能访问子类特有的特性
final关键字
final修饰的类不可以被继承;
内部类
1.成员内部类
成员内部类的定义格式:
public class 类名称{
public class 类名称{
}
}
Map集合
map集合是双列集合,常用的方法如下:
新建一个map集合对象
map<String,String> map = new HashMap<>();
向map集合中添加元素
map.put("键","值")
根据键取值
String value = map.get("key")
根据键删除值
String value = map.remove("key")
遍历map集合
首先将集合中的key放到一个set集合中,然后根据key值进行遍历value值
例子
①根据增强for进行遍历
Set<String> keys = map.keySet();
for(String key:keys){
String value = map.get(key);
}
②使用迭代器进行遍历
Set<String> keys = map.keySet();
Iterator<String> iterator = keys.iterator();
while (iterator.hasNext()){
String key = iterator.next();
String value = map.get(key);
System.out.println(value);
}
map集合遍历键值对的方式
当map集合一创建,就会在map集合中创建Entry对象,用来记录键与值的映射关系
public class mapEntry {
public static void main(String[] args) {
Map<String, Integer> map = new HashMap<>();
map.put("小明",123);
map.put("小红",193);
map.put("小丽",333);
//使用map集合中的entrySet()方法将map集合中多个Entry对象取出来放到Set集合中
Set<Map.Entry<String, Integer>> entries = map.entrySet();
//使用迭代器进行遍历
Iterator<Map.Entry<String, Integer>> it = entries.iterator();
while (it.hasNext()){
Map.Entry<String, Integer> entry = it.next();
String key = entry.getKey();
Integer value = entry.getValue();
System.out.println(key);
System.out.println(value);
}
}
}
HashMap和LinkedHashMap区别:
key都不可以重复
HashMap取的时候无序
LinkedHashMap取的时候按照存的顺序
经典案例分析
题目:统计一个字符串中字符出现的次数
分析:1.获取一个字符串,键盘输入
2.(使用map集合)遍历字符串中的字符并判断是否在map集合中已存在,若存在,则value值+1,否则新增key,并且value值设置为1
import java.util.*;
public class CharCount {
public static void main(String[] args) {
System.out.println("请输入一串字符串:");
Scanner scanner = new Scanner(System.in);
String s = scanner.next();
// 获取到每一个字符
char[] array = s.toCharArray();
HashMap<Character,Integer> map = new HashMap<>();
// 遍历每一个字符
for (int i = 0; i < array.length; i++) {
// 判断该字符是否存在map集合中
boolean b = map.containsKey(array[i]);
// 如果存在,则value值+1
if (b==true){
Integer value = map.get(array[i]);
value++;
// 把新的value存储到map集合中
map.put(array[i],value);
}else{
// 若不存在,则把key值存储到map集合中,并设置value值为1
map.put(array[i],1);
}
}
// 遍历map集合。下面使用的是迭代器遍历
Set<Map.Entry<Character, Integer>> entries = map.entrySet();
Iterator<Map.Entry<Character, Integer>> iterator = entries.iterator();
while (iterator.hasNext()){
Map.Entry<Character, Integer> entry = iterator.next();
Character key = entry.getKey();
Integer val = entry.getValue();
System.out.println(key);
System.out.println(val);
}
}
}
子父类异常的处理:
1、如果父类抛出了多个异常,子类重写父类方法时,抛出和父类相同的异常或者不抛出异常。
2、父类方法没有抛出异常,子类重写父类方法时也不可抛出异常,此时子类产生该异常,只能捕获处理,不能声明抛出
注意:父类异常是什么样子,子类异常就是什么样子
自定义异常:
/**
* 自定义异常类,java提供的异常类不够我们使用,所以需要自己定义
* 格式 public class XXXException extends Exception |RuntimeException{
* 添加一个空参的构造方法
* 添加一个带异常信息的构造方法
* }
*/
public class RegisterException extends Exception{
public RegisterException(){
}
public RegisterException(String message){
super(message);
}
}
自定义异常案例:
import java.util.Scanner;
/**
* 模拟注册操作,如果用户名已存在,则抛出异常提示:亲,该用户名已被注册
* 分析
* 1.首先需要把已有的用户名放到一个数组中
* 2.键盘输入输入的用户名
*/
public class RegisterExceptionDemo {
static String[] tel = {"13800000001", "13800000002", "13800000003"};
public static void main(String[] args){
Scanner scanner = new Scanner(System.in);
System.out.println("请输入用户注册手机号:");
// 输入注册手机号
String new_tel = scanner.next();
checkUserTel(new_tel);
}
public static void checkUserTel(String new_tel) {
for (String exist_tel : tel) {
if (exist_tel.equals(new_tel)){
try {
throw new RegisterException("亲,该用户名已被注册");
} catch (RegisterException e) {
e.printStackTrace();
}
return;
// return的作用就是结束方法
}
}
System.out.println("注册成功");
}
}
多线程
并发:两个或多个事件在同一时间段内发生(交替发生)
并行:两个或多个事件在同一时刻发生
进程:进入到内存中的应用程序
线程:一个进程可以包含多个线程(比如电脑管家中有清理垃圾、病毒查杀、电脑加速等)
创建多线程的步骤:
//创建一个Thread类的子类
public class MyThread extends Thread {
// 重写Thread的run方法,目的就是设置线程任务
@Override
public void run() {
for (int i = 0; i < 20; i++) {
System.out.println("run"+i);
}
}
}
/**
* 创建多线程的步骤
* 1、创建一个Thread类的子类
* 2、在Thread类的子类中重写Thread类中的run方法,设置线程任务(开启线程要做什么)
* 3、创建Thread类的子类对象
* 4、调用Thread类的方法start方法,开启新的线程,执行run方法
*/
public class Demo01Thread {
public static void main(String[] args) {
MyThread thread = new MyThread();
thread.start();
for (int i = 0; i <20 ; i++) {
System.out.println("main"+i);
}
}
}
创建多线程的第二种方法:
/**
* 创建多线程的第二种方法:实现Runnable接口
* 步骤如下:
* 1.创建一个Runnable接口的实现类
* 2、在实现类中重写run方法,设置线程任务
* 3、创建一个Runnable接口的实现类对象
* 4、创建Thread类对象,构造方法中传递Runnable接口的实现类对象
* 5.调用Thread类中的start方法,开启新的线程执行run方法
*/
public class Demo01Runnable implements Runnable{
@Override
public void run() {
for (int i = 0; i < 20; i++) {
System.out.println(Thread.currentThread().getName()+i);
}
}
}
public class RunnableObject {
public static void main(String[] args) {
Demo01Runnable runnable = new Demo01Runnable();
Thread t = new Thread(runnable);
t.start();
for (int i = 0; i < 20; i++) {
System.out.println(Thread.currentThread().getName()+"--->"+i);
}
}
}
Thread和Runnable的区别:
如果一个类继承Thread则不适合资源共享,但是如果实现了Runnable接口的话,则很容易实现资源共享。
实现Runnable接口比继承Thread类所具有的优势:
1.适合多个相同的程序代码的线程去共享同一资源
2.可以避免java中的单继承的局限性(一个类只能继承一个类,一个类继承了Thread类就不能继承其他的类,如果实现了Runnable接口,还可以继承其他的类,实现其他接口)
3.增加程序的健壮性、实现解耦合操作,代码可以被多个线程共享,代码和线程独立
4、线程池只能放入实现Runnable或Callable类线程,不能直接放入继承Thread的类
获取线程名称的方式:
public class Demo02Thread {
public static void main(String[] args) {
MyThread01 myThread01 = new MyThread01();
myThread01.start();
new MyThread01().start();
new MyThread01().start();
}
}
public class MyThread01 extends Thread {
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
}
匿名内部类实现线程的创建
匿名:没有名字
内部类:写在其他类内部的类
匿名内部类的作用:简化代码
把子类继承父类,重写父类方法,创建子类对象合一步完成
把实现类实现接口,重写接口中的方法,创建实现类对象合成一步完成
匿名内部类的最终产物:
子类/实现类对象,而这个类没有名字
格式:
new 父类/接口(){
重写父类/接口中的方法
}.start()
解决线程安全问题
为了保证每个线程都能正常执行原子操作,java引入了线程同步机制
有三种方式完成同步操作:
1.同步代码块
2.同步方法
3.锁机制
1.同步代码块
格式
synchronized (锁对象){
可能会出现线程安全的代码(访问了共享数据的代码)
}
注意:
1.同步代码块中的对象可以是任意的对象
2.必须保证多个线程使用的锁对象是同一个
3.锁对象作用:
把同步代码块锁住,只让一个线程在同步代码块中执行
//卖票案例
public class Ticket implements Runnable{
private int ticket = 100;
//创建一个对象
Object object = new Object();
@Override
public void run() {
while (true){
synchronized (object){
if (ticket>0){
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"正在卖第"+ticket+"张票");
ticket--;
}
}
}
}
}
public class DemoTicket {
public static void main(String[] args) {
Ticket ticket = new Ticket();
Thread thread01 = new Thread(ticket);
Thread thread02 = new Thread(ticket);
Thread thread03 = new Thread(ticket);
thread01.start();
thread02.start();
thread03.start();
}
}
2.同步方法
格式:
修饰符 synchronized 返回值类型 方法名(参数列表){
}
3.lock锁
lock实现提供了比使用synchronized方法和语句可获得的更广泛的锁操作