【C++】反向迭代器

news2025/7/12 7:56:01

文章目录

  • 一、什么是反向迭代器
  • 二、STL 源码中反向迭代器的实现
  • 三、reverse_iterator 的模拟实现
  • 四、vector 和 list 反向迭代器的实现

一、什么是反向迭代器

C++ 中一共有四种迭代器 – iterator、const_iterator、reverse_iterator 以及 const_reverse_iterator,其中正向迭代器我们已经很熟悉了,其实反向迭代器的使用和正向迭代器几乎一样,反向迭代器的特点如下:

  • rbegin() 相当于 end();
  • rend() 相当于 begin();
  • 反向迭代器++相当于正向迭代器–;
  • 其他操作比如 * != -> 和正向迭代器相同。

image-20230305225853889

反向迭代器的使用:反向迭代器的使用和正向迭代器完全相同

void reverse_iterator_test() {
	vector<int> v;
	v.push_back(1);
	v.push_back(5);
	v.push_back(6);
	v.push_back(5);
	v.push_back(9);

	vector<int>::reverse_iterator rit = v.rbegin();
	while (rit != v.rend()) {
		(*rit) += 1;
		cout << *rit << " ";
		++rit;
	}
	cout << endl;
}

image-20230305230529998

在以前 string、vector 和 list 中模拟实现中我们只实现了正向迭代器,而并没有去实现反向迭代器,今天我们就来探究如何实现反向迭代器。


二、STL 源码中反向迭代器的实现

我们可以通过参考 STL 源码中反向迭代器的实现方式来学习如何实现反向迭代器,如下:

//list.h部分源码 -- SGI版
template <class T, class Alloc = alloc>
class list {
public:
	typedef __list_iterator<T, T&, T*>             iterator;
	typedef __list_iterator<T, const T&, const T*> const_iterator;

#ifdef __STL_CLASS_PARTIAL_SPECIALIZATION
	typedef reverse_iterator<const_iterator> const_reverse_iterator;
	typedef reverse_iterator<iterator> reverse_iterator;
//vector.h部分源码 -- SGI版
template <class T, class Alloc = alloc>
class vector {
public:
  typedef T value_type;
  typedef value_type* iterator;
  typedef const value_type* const_iterator;

#ifdef __STL_CLASS_PARTIAL_SPECIALIZATION
  typedef reverse_iterator<const_iterator> const_reverse_iterator;
  typedef reverse_iterator<iterator> reverse_iterator;

可以看到,STL 源码中 vector 和 list 的反向迭代器都是 reverse_iterator 类的 typedef,而 reverse_iterator 类位于源码中的 stl_iterator.h 中,其部分源码如下:

//stl_iterator.h -- SGI版
template <class Iterator>
class reverse_iterator {
protected:
  Iterator current;
    
public:
  typedef Iterator iterator_type;
  typedef reverse_iterator<Iterator> self;

public:
  reverse_iterator() {}
  explicit reverse_iterator(iterator_type x) : current(x) {}
  reverse_iterator(const self& x) : current(x.current) {}
  reference operator*() const {
    Iterator tmp = current;
    return *--tmp;
  }
#ifndef __SGI_STL_NO_ARROW_OPERATOR
  pointer operator->() const { return &(operator*()); }
#endif /* __SGI_STL_NO_ARROW_OPERATOR */

  self& operator++() {
    --current;
    return *this;
  }
  self& operator--() {
    ++current;
    return *this;
  }
  //...
}

image-20230306141315238

image-20230306141334814

如上,正向迭代器是 reverse_iterator 的模板参数,而反向迭代器是 reverse_iterator 的对象,所以反向迭代器是一个容器适配器,它的适配容器就是对应的正向迭代器,这样它就能根据传递过来的正向迭代器的不同实例化出对应的反向迭代器

也就是说,只要实现了 reverse_iterator 类,以后不管是 vector、list、map 还是其他的容器,只要你将其对应的正向迭代器传递给我,我就能适配出对应的反向迭代器,做到泛型编程。


三、reverse_iterator 的模拟实现

模拟实现代码:iterator.h

#pragma once

namespace thj {
	template<class Iterator, class Ref, class Ptr>
	class reverse_iterator {
		typedef reverse_iterator<Iterator, Ref, Ptr> self;
	public:
		reverse_iterator(Iterator it)   //构造
			: _it(it)
		{}

		self& operator++() {  //++
			--_it;
			return *this;
		}

		self operator++(int) {  //后置++  返回值不加引用,因为tmp是局部变量
			Iterator tmp = _it;
			--_it;
			return tmp;
		}

		self& operator--() {  //--
			++_it;
			return *this;
		}

		self operator--(int) {  //后置--  返回值不加引用
			Iterator tmp = _it;
			++_it;
			return tmp;
		}

		bool operator!=(const self& s) const {  //不等于
			return _it != s._it;
		}

		Ref operator*() {  //解引用,返回的是反向迭代器的前一个位置
			Iterator tmp = _it;
			return *(--tmp);
		}

		Ptr operator->() {  //-> 返回节点数据的地址
			return &(operator*());
		}

	private:
		Iterator _it;  //成员变量是正向迭代器
	};
}

模拟实现细节

1、由于 rbegin() 等价于 end(),rend() 等价于 begin(),所以 ++reverse_iterator 等价于 --iteraor,–reverse_iterator 等价于 ++iterator;

2、在实现 operator*() 和 operator->() 时我们并不知道 T 的类型 (const 与非 const),所以我们不能确定函数的返回值;STL 源码中使用迭代器萃取的方法来解决这个问题,如下:

//stl_iterator.h部分源码
template <class Iterator>
class reverse_iterator
{
    // iterator_traits -- 迭代器萃取
    typedef typename iterator_traits<Iterator>::pointer
  	typedef typename iterator_traits<Iterator>::reference reference;
    reference operator*() const {
        Iterator tmp = current;
        return *--tmp;
    }
#ifndef __SGI_STL_NO_ARROW_OPERATOR
	pointer operator->() const { return &(operator*()); }
};

但是这种方式十分复杂,并且校招的时候并不会考察萃取相关的知识,所以这里我们参考 list 正向迭代器 的设计思路 – 增加两个模板参数分别作为 operator*() 和 operator->() 函数的返回值,如下:

//typedef reverse_iterator<Iterator, T&, T*> reverse_iterator 反向迭代器
//typedef const_reverse_iterator<Iterator, const T&, const T*> const_reverse_iterator const反向迭代器

template<class Iterator, class Ref, class Ptr>
class reverse_iterator {
    typedef reverse_iterator<Iterator, Ref, Ptr> self;
    public:
    Ref operator*() {  //解引用,特别注意:返回的是反向迭代器的前一个位置
        Iterator tmp = _it;
        return *(--tmp);
    }
    Ptr operator->() {  //-> 返回节点数据的地址
        return &(operator*());
    }
    private:
    Iterator _it;  //成员变量是正向迭代器
};

3、同时,由于 end 是指向最后一个元素的下一个位置,而 rbegin 由 end 适配得到,所以反向迭代器中 operator*() 不是返回迭代器当前位置的数据,而是返回迭代器前一个位置的数据,不然会发生越界访问。


四、vector 和 list 反向迭代器的实现

现在我们已经实现了 reverse_iterator 类,所以可以直接用 vector 和 list 的正向迭代器作为 reverse_iterator 的适配容器适配出它们的反向迭代器。

vector 反向迭代器

反向迭代器相关代码:

#include "iterator.h"
template<class T>
	class list
	{
		//反向迭代器
		typedef thj::reverse_iterator<iterator, T&, T*> reverse_iterator;
		typedef thj::reverse_iterator<const_iterator, const T&, const T*> const_reverse_iterator;

		reverse_iterator rbegin() {
			return reverse_iterator(end());
		}

		reverse_iterator rend() {
			return reverse_iterator(begin());
		}

		const_reverse_iterator rbegin() const {
			return const_reverse_iterator(end());
		}

		const_reverse_iterator rend() const {
			return const_reverse_iterator(begin());
		}
	};
}

list.h:

#pragma once

#include <assert.h>
#include <algorithm>
#include "iterator.h"

namespace thj {
	template<class T>
	struct list_node
	{
		list_node<T>* _next;//不加<T>也没错,但是写上好一些
		list_node<T>* _prev;
		T _data;

		list_node(const T& x)//构造
			:_next(nullptr)
			, _prev(nullptr)
			, _data(x)
		{}
	};

	//迭代器最终版
	//const 迭代器 -- 增加模板参数,解决 operator*() 返回值与 operator->() 返回值问题
	//typedef __list_iterator<T, T&, T*> iterator;
	//typedef __list_iterator<T, const T&, const T*> const_iterator;
	//STL源码中大佬的写法,利用多个模板参数来避免副本造成的代码冗余问题
	template<class T, class Ref, class Ptr>
	struct __list_iterator  //迭代器类
	{
		typedef list_node<T> node;  //重命名list节点
		typedef __list_iterator<T, Ref, Ptr> Self;  //这里进行重命名是为了后续再添加模板参数时只用修改这一个地方
		node* _pnode;  //节点指针作为类的唯一成员变量

		__list_iterator(node* p)
			:_pnode(p)
		{}

		Ref operator*()  //解引用
		{
			return _pnode->_data;
		}

		Ptr operator->()  //->
		{
			return &_pnode->_data;
		}

		Self& operator++() //前置++
		{
			_pnode = _pnode->_next;
			return *this;
		}

		Self& operator++(int) //后置++
		{
			Self it(*this);
			_pnode = _pnode->_next;
			return it;
		}

		Self& operator--() //前置--
		{
			_pnode = _pnode->_prev;
			return *this;
		}

		Self& operator--(int) //后置--
		{
			Self it(*this);
			_pnode = _pnode->_prev;
			return it;
		}

		bool operator!=(const Self& it) const //!=
		{
			return _pnode != it._pnode;
		}

		bool operator==(const Self& it) const  //==
		{
			return _pnode == it._pnode;
		}
	};

	//list 类
	template<class T>
	class list
	{
		typedef list_node<T> node;
	public:
		typedef __list_iterator<T, T&, T*> iterator;  //迭代器
		typedef __list_iterator<T, const T&, const T*> const_iterator; //const 迭代器

		//反向迭代器
		typedef thj::reverse_iterator<iterator, T&, T*> reverse_iterator;
		typedef thj::reverse_iterator<const_iterator, const T&, const T*> const_reverse_iterator;

		reverse_iterator rbegin() {
			return reverse_iterator(end());
		}

		reverse_iterator rend() {
			return reverse_iterator(begin());
		}

		const_reverse_iterator rbegin() const {
			return const_reverse_iterator(end());
		}

		const_reverse_iterator rend() const {
			return const_reverse_iterator(begin());
		}

		//迭代器
		iterator begin() {
			return iterator(_head->_next);
		}

		iterator end() {
			//iterator it(_head);
			//return it;

			//直接利用匿名对象更为便捷
			return iterator(_head);
		}

		const_iterator begin() const {
			return const_iterator(_head->_next);
		}

		const_iterator end() const {
			return const_iterator(_head);
		}

		void empty_initialize() {  //初始化 -- 哨兵位头结点
			_head = new node(T());
			_head->_next = _head;
			_head->_prev = _head;

			_size = 0;  //空间换时间,用于标记节点个数
		}

		list() {  //构造,不是list<T>的原因:构造函数函数名和类名相同,而list<T>是类型
			empty_initialize();
		}

		//迭代器区间构造
		template <class InputIterator>
		list(InputIterator first, InputIterator last) {
			empty_initialize();
			while (first != last)
			{
				push_back(*first);
				++first;
				//first++;
			}
		}

		// 拷贝构造的现代写法
		//list(const list& lt) 官方库是这样写的,这是由于在类内类名等价于类型,但不建议自己这样写
		list(const list<T>& lt) {
			empty_initialize();  //初始化头结点,防止交换后tmp野指针不能正常的调用析构
			list<T> tmp(lt.begin(), lt.end());
			swap(tmp);
		}

		//赋值重载现代写法
		//list& operator=(list lt)
		list<T>& operator=(list<T> lt) {  //不能加引用,lt是调用拷贝构造生成的
			swap(lt);
			return *this;
		}

		~list() {  //析构
			clear();
			delete _head;
			_head = nullptr;
		}

		void swap(list<T>& lt) {  //交换两个链表,本质上是交换两个链表的头结点
			std::swap(_head, lt._head);
			std::swap(_size, lt._size);
		}

		size_t size() const {  //增加一个计数的成员,以空间换时间
			return _size;
		}

		bool empty() {  //判空
			return _size == 0;
		}

		void clear() {
			iterator it = begin();
			while (it != end()) {
				it = erase(it);
			}
			_size = 0;
		}

		void push_back(const T& x) {
			insert(end(), x);  //复用
		}

		void push_front(const T& x) {
			insert(begin(), x);  //复用
		}

		void pop_front() {
			erase(begin());
		}

		void pop_back() {
			erase(--end());
		}

		iterator insert(iterator pos, const T& x) {
			node* newnode = new node(x);
			node* cur = pos._pnode;
			node* prev = cur->_prev;

			prev->_next = newnode;
			newnode->_prev = prev;
			cur->_prev = newnode;
			newnode->_next = cur;

			++_size;
			return iterator(pos);
		}

		iterator erase(iterator pos) {
			assert(pos != end());

			node* prev = pos._pnode->_prev;
			node* next = pos._pnode->_next;

			prev->_next = next;
			next->_prev = prev;
			delete pos._pnode;

			--_size;
			return iterator(next);
		}

	private:
		node* _head;
		size_t _size;
	};
}

test.cpp:

void list_reverse_iterator_test() {
	thj::list<int> lt;
	lt.push_back(1);
	lt.push_back(2);
	lt.push_back(3);
	lt.push_back(4);
	lt.push_back(5);

	thj::list<int>::reverse_iterator rit = lt.rbegin();  //反向迭代器
	while (rit != lt.rend()) {
		(*rit)++;
		cout << *rit << " ";
		++rit;
	}
	cout << endl;

	const thj::list<int> clt(lt.begin(), lt.end());
	thj::list<int>::const_reverse_iterator crit = clt.rbegin();  //const反向迭代器
	while (crit != clt.rend()) {
		//(*crit)++;
		cout << *crit << " ";
		++crit;
	}
	cout << endl;
}

image-20230306153224898

vector 反向迭代器

反向迭代器相关代码:

namespace thj {
	template<class T>
	class vector {
	public:
        //正向迭代器
		typedef T* iterator;
		typedef const T* const_iterator;

		//反向迭代器 -- 容器适配器
		typedef thj::reverse_iterator<iterator, T&, T*> reverse_iterator;
		typedef thj::reverse_iterator<const_iterator, const T&, const T*> const_reverse_iterator;

		reverse_iterator rbegin() {
			return reverse_iterator(end());
		}

		reverse_iterator rend() {
			return reverse_iterator(begin());
		}

		const_reverse_iterator rbegin() const {
			return const_reverse_iterator(end());
		}

		const_reverse_iterator rend() const {
			return const_reverse_iterator(begin());
		}
    };
}

vector.h:

#pragma once
#include <iostream>
#include <assert.h>
#include <string.h>
#include <algorithm>
#include "iterator.h"

namespace thj {
	template<class T>
	class vector {
	public:
		//正向迭代器
		typedef T* iterator;
		typedef const T* const_iterator;

		iterator begin() {
			return _start;
		}

		iterator end() {
			return _finish;
		}

		const_iterator begin() const {
			return _start;
		}

		const_iterator end() const {
			return _finish;
		}

		//反向迭代器 -- 容器适配器
		//反向迭代器 -- 容器适配器
		typedef thj::reverse_iterator<iterator, T&, T*> reverse_iterator;
		typedef thj::reverse_iterator<const_iterator, const T&, const T*> const_reverse_iterator;

		reverse_iterator rbegin() {
			return reverse_iterator(end());
		}

		reverse_iterator rend() {
			return reverse_iterator(begin());
		}

		const_reverse_iterator rbegin() const {
			return const_reverse_iterator(end());
		}

		const_reverse_iterator rend() const {
			return const_reverse_iterator(begin());
		}

	public:
		//---------------------------constructor------------------------------//
		//无参构造
		vector()
			:_start(nullptr)
			, _finish(nullptr)
			, _end_of_storage(nullptr)
		{}

		//迭代器区间构造
		template<class InputIterator>
		vector(InputIterator first, InputIterator last)
			:_start(nullptr)
			, _finish(nullptr)
			, _end_of_storage(nullptr)
		{
			while (first != last)
			{
				push_back(*first);
				++first;
			}
		}

		//n个val构造
		vector(size_t n, const T& val = T())
			:_start(nullptr)
			, _finish(nullptr)
			, _end_of_storage(nullptr)
		{
			reserve(n);
			for (size_t i = 0; i < n; i++)
				push_back(val);
		}

		//n个val构造 -- 重载
		vector(int n, const T& val = T())
			:_start(nullptr)
			, _finish(nullptr)
			, _end_of_storage(nullptr)
		{
			reserve(n);
			for (int i = 0; i < n; i++)
				push_back(val);
		}

		//拷贝构造 -- 现代写法
		vector(const vector<T>& v)
			:_start(nullptr)
			, _finish(nullptr)
			, _end_of_storage(nullptr)
		{
			vector<T> tmp(v.begin(), v.end());  //复用构造函数和swap函数
			swap(tmp);
		}

		//析构函数
		~vector() {
			delete[] _start;
			_start = _finish = _end_of_storage = nullptr;
		}

		//赋值重载
		vector<T>& operator=(vector<T> v)  //复用拷贝构造,存在自我赋值的问题,但不影响程序正确性
		{
			swap(v);
			return *this;
		}

		//---------------------------------capacity------------------------------------//
		size_t size() const
		{
			return _finish - _start;
		}

		size_t capacity() const
		{
			return _end_of_storage - _start;
		}

		bool empty() const
		{
			return _start == _finish;
		}

		//扩容
		void reserve(size_t n)
		{
			if (n > capacity())  //reserve 函数不缩容
			{
				T* tmp = new T[n];
				//memcpy(tmp, _start, sizeof(T) * size());  //error

				//memcpy有自定义类型的浅拷贝问题,需要对每个元素使用拷贝构造进行深拷贝
				for (int i = 0; i < size(); i++)
					tmp[i] = _start[i];  //拷贝构造

				size_t oldSize = _finish - _start;  //记录原来的size,避免扩容不能确定_finish
				delete[] _start;

				_start = tmp;
				_finish = _start + oldSize;
				_end_of_storage = _start + n;
			}
		}

		//扩容并初始化
		void resize(size_t n, T x = T())
		{
			if (n > capacity())  //resize 不缩容
			{
				reserve(n);
			}
			if (n > size())
			{
				while (_finish < _start + n)
				{
					*_finish = x;
					++_finish;
				}
			}
			if (n < size())
			{
				_finish = _start + n;
			}
		}

		//------------------------------element access-------------------//
		T& operator[](size_t pos)
		{
			assert(pos < size());  //检查越界
			return _start[pos];
		}

		const T& operator[](size_t pos) const
		{
			assert(pos < size());
			return _start[pos];
		}

		//----------------------------------modifys-----------------------------------//
		//尾插
		void push_back(const T& n)
		{
			if (size() == capacity())
			{
				size_t newCapacity = capacity() == 0 ? 4 : capacity() * 2;
				reserve(newCapacity);
			}
			*_finish = n;
			++_finish;
		}

		//尾删
		void pop_back()
		{
			assert(!empty());
			--_finish;
		}

		//任意位置插入
		iterator insert(iterator pos, const T& x)
		{
			assert(pos >= _start);
			assert(pos <= _finish);

			//扩容导致 pos 迭代器失效
			if (size() == capacity())
			{
				size_t oldPos = pos - _start;  //记录pos,避免扩容后pos变为野指针
				size_t newCapacity = capacity() == 0 ? 4 : capacity() * 2;
				reserve(newCapacity);
				pos = _start + oldPos;  //扩容之后更新pos
			}

			iterator end = _finish - 1;
			while (end >= pos)
			{
				*(end + 1) = *end;
				--end;
			}

			*pos = x;
			++_finish;
			return pos;
		}

		//任意位置删除 -- erase 之后也认为 pos 迭代器失效
		iterator erase(iterator pos)
		{
			assert(pos >= _start);
			assert(pos < _finish);

			iterator begin = pos;
			while (begin < _finish - 1)
			{
				*begin = *(begin + 1);
				++begin;
			}
			--_finish;
			return pos;
		}

		//交换两个对象
		void swap(vector<T>& v)
		{
			std::swap(_start, v._start);  //复用算法库的swap函数
			std::swap(_finish, v._finish);
			std::swap(_end_of_storage, v._end_of_storage);
		}

		void clear()
		{
			_finish = _start;
		}

	private:
		T* _start;
		T* _finish;
		T* _end_of_storage;
	};
}

test.cpp:

void vector_reverse_iterator_test() {
	thj::vector<int> v;
	v.push_back(1);
	v.push_back(2);
	v.push_back(3);
	v.push_back(4);
	v.push_back(5);

	thj::vector<int>::reverse_iterator rit = v.rbegin();
	while (rit != v.rend()) {
		(*rit)++;
		cout << *rit << " ";
		++rit;
	}
	cout << endl;

	const thj::vector<int> cv(v.begin(), v.end());
	thj::vector<int>::const_reverse_iterator crit = cv.rbegin();
	while (crit != cv.rend()) {
		//(*crit)++;
		cout << *crit << " ";
		++crit;
	}
	cout << endl;
}

image-20230306161811850


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/396167.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

基层治理四平台解决方案

本资料来源公开网络&#xff0c;仅供个人学习&#xff0c;请勿商用。部分资料内容&#xff1a; 省基层治理体系“四个平台”采用“1N"统分结合的建设模式:即统筹建设“1"个浙江政务服务网基层业务协同平台(以下简称“协同平台”)&#xff0c;同步改造、整合、推广“N…

【java】Collection源码阅读(JDK 8)

package java.util;import java.util.function.Predicate; import java.util.stream.Stream; import java.util.stream.StreamSupport;/*** 集合层次结构的根接口&#xff0c;一个集合表示一组对象&#xff0c;称为元素* JDK不提供任何该接口的直接实现&#xff0c;JDK提供实现…

Elasticsearch 核心技术(六):内置的 8 种分词器详解 + 代码示例

❤️ 博客主页&#xff1a;水滴技术 &#x1f680; 支持水滴&#xff1a;点赞&#x1f44d; 收藏⭐ 留言&#x1f4ac; &#x1f338; 订阅专栏&#xff1a;大数据核心技术从入门到精通 文章目录一、内置分词器1. Standard&#xff08;标准分词器&#xff09;英文示例中文示例…

八.异常控制流ECF

1.异常异常位于硬件和OS的交界部分系统调用是为应用程序提供到OS的入口点的异常进程和信号位于应用和OS的交界部分非本地跳转是ECF的应用层形式1.1 异常表异常是控制流中的突变&#xff0c;用来响应处理器状态的某些变化状态变化称为事件系统中可能的每种类型的异常都分配了一个…

虹科教您 | 在Windows环境下安装PCAN View及通讯测试指南

应用简介 PCAN-View软件是一款简化的CAN监视软件&#xff0c;可用于显示、发送、和记录CAN数据通讯。报文可手动和定期发送&#xff0c;用户可设置比特率。在处理期间显示总线系统错误和CAN硬件的存储器过满。示踪功能可用于记录和保存CAN数据通讯。本文档的作用在于&#xff…

软件测试的几个关键步骤,你需要知道

记得2年前刚毕业的时候听说了软件测试这个行业&#xff0c;当时也去百度仔细进行了一番搜索&#xff0c;评价基本千篇一律的看好。 看好的原因在于&#xff0c;专家认为未来的互联网市场用户体验至上&#xff0c;而产品质量与用户体验有紧密的联系&#xff0c;自从近年产品经理…

eyoucms field 获取channelartlist标签的字段值

【基础用法】 标签&#xff1a;field 描述&#xff1a;获取channelartlist标签里的字段值&#xff0c;field标签只能在channelartlist标签里使用。 用法&#xff1a; {eyou:channelartlist typeid栏目ID typeson row20} <a href{eyou:field nametypeurl /}>{eyou:fi…

SCCM 应用程序管理

Microsoft System Center Configuration Manager &#xff08;SCCM&#xff09; 被认为是管理 Microsoft 应用程序的示例性工具。它可以无缝地进行补丁管理和软件部署。但处理第三方应用程序不是它的游戏。因此&#xff0c;除了补丁管理之外&#xff0c;Patch Connect Plus 还为…

接口里面可以写实现方法吗【可以】 、接口可以多继承吗【可以】

比如下面这道题&#xff1a; 问: 接口里面可以写方法吗&#xff1f; 答: 当然可以啊&#xff0c;默认就是抽象方法。 . 问&#xff1a; 那接口里面可以写实现方法吗&#xff1f; 答&#xff1a; 不可以&#xff0c;所有方法必须是抽象的。 . 问&#xff1a; 你确定吗&#xff1…

Java面试题--SpringRefresh流程

Spring refresh 概述 Spring 容器是一个管理 bean 的容器&#xff0c;可以创建、注入和管理 bean 及其依赖关系。Spring 容器可以根据应用程序配置和运行时条件创建、初始化和销毁 bean。refresh() 函数是 Spring 容器中的一种功能&#xff0c;可以重新加载和刷新容器中的配置…

什么?同步代码块失效了?-- 自定义类加载器引起的问题

一、背景 最近编码过程中遇到了一个非常奇怪的问题&#xff0c;基于单例对象的同步代码块似乎失效了&#xff0c;百思不得其姐。 下面给出模拟过程和最终的结论。 二、场景描述和模拟 2.1 现象描述 Database实现单例&#xff0c;在 init 方法中使用同步代码块来保证 data不…

Revit中图纸要怎么布局呢?

1、明确图纸布局原则。 2、在图纸上锁定视图的位置 在图纸上放置视图(或明细表)并根据需要对其定位后&#xff0c;可以将其锁定到位&#xff0c;这样就不会在无意中移动它。如果想要解锁视图&#xff0c;单击锁定图标即可&#xff0c;如图1所示。 3、在图纸上旋转视图 可以在图…

imx6 usb增强信号强度

USB信号 参考&#xff1a;官方文档 USB信号完整性取决于许多因素&#xff0c;如电路设计、PCB布局、堆叠和阻抗。每个产品可能彼此不同&#xff0c;因此客户需要微调参数&#xff0c;以获得最佳的信号质量。 测试板已经路由出两个USB端口:一个OTG1&#xff0c;一个主机。每个端…

xcode14安装swift package设置github账户token

这里写目录标题登录github账户,复制token打开xcode添加github账户选择swift package登录github账户,复制token 登录github点击上面菜单自己的头像,settings->Developer settings->Personal access tokens->Tokens (classic)->Generate new token (classic) Note名…

Spring 响应式编程-读书笔记

序言 大家好&#xff0c;我是比特桃。本文为《Spring 响应式编程》的读书笔记&#xff0c;响应式技术栈可以创建极其高效、易于获取且具有回弹性的端点&#xff0c;同时响应式可以容忍网络延迟&#xff0c;并以影响较小的方式处理故障。响应式微服务还可以隔离慢速事务并加速速…

判断推理之图形推理

考点一动态位置变化&#xff08;一&#xff09;平移1.特征&#xff1a;图形在平面上的移动&#xff0c;图形本身的大小和形状不发生改变。2.方向&#xff1a;直线&#xff08;上下、左右、斜对角线&#xff09;&#xff0c;绕圈&#xff08;顺时针、逆时针&#xff09;3.距离&a…

聚观早报 |王兴宣布美团网约车业务调整;软银Arm被曝4月申请上市

今日要闻&#xff1a;王兴宣布美团网约车业务调整&#xff1b;钉钉收购协同办公厂商「我来 wolai」&#xff1b;软银旗下Arm被曝4月申请上市&#xff1b;小米汽车完成冬测&#xff1b;淘特负责人否认将被合并到淘宝 王兴宣布美团网约车业务调整 美团创始人王兴发布内部信&#…

蓝桥杯入门即劝退(二十六)组合问题(回溯算法)

-----持续更新Spring入门系列文章----- 如果你也喜欢Java和算法&#xff0c;欢迎订阅专栏共同学习交流&#xff01; 你的点赞、关注、评论、是我创作的动力&#xff01; -------希望我的文章对你有所帮助-------- 专栏&#xff1a;蓝桥杯系列 一、题目描述 给定两个整数 n …

css:使用filter和backdrop-filter实现高斯模糊效果

背景 今天接到一个需求是&#xff0c;使用高斯模糊的效果对一个页面进行模糊处理&#xff0c;正好借这个机会来整理一下 css3 中高斯模糊的两个 API API介绍 filter 说明&#xff1a; 该 API 是一个过滤器&#xff0c;不仅能实现高斯模糊&#xff0c;还有很多比如颜色偏移、…

【Linux】网络基础(1)

前言 相信没有网络就没有现在丰富的世界。本篇笔记记录我在Linux系统下学习网络基础部分知识&#xff0c;从关于网络的各种概念和关系开始讲起&#xff0c;逐步架构起对网络的认识&#xff0c;对网络编程相关的认知。 我的上一篇Linux文章呀~ 【Linux】网络套接字编程_柒海啦的…